Skip to main content
Added P.S. items about "::" notation and .NET methods
Source Link
Solomon Rutzky
  • 69.5k
  • 8
  • 155
  • 300

P.S. The solution shown above (i.e. splitting on the colons) does not handle the "reduced" notation / syntax whereby "::" can be substituted for one or more consecutive ranges of "0000". For example: 2600:100:400::0. Hence, that solution requires that all 8 segments exist with at least "0" in them.

P.P.S. If you are using .NET either in the app or SQLCLR or SSIS, you can use a combination of IPAddress.TryParse and IPAddress.GetAddressBytes to handle the reduced "::" notation. Or, you could always write a bunch of code to handle it in pure T-SQL.

P.P.P.S. INET_IPv6toBinary will be available in the next release (version 4.3) of SQL# :-)

P.S. The solution shown above (i.e. splitting on the colons) does not handle the "reduced" notation / syntax whereby "::" can be substituted for one or more consecutive ranges of "0000". For example: 2600:100:400::0. Hence, that solution requires that all 8 segments exist with at least "0" in them.

P.P.S. If you are using .NET either in the app or SQLCLR or SSIS, you can use a combination of IPAddress.TryParse and IPAddress.GetAddressBytes to handle the reduced "::" notation. Or, you could always write a bunch of code to handle it in pure T-SQL.

P.P.P.S. INET_IPv6toBinary will be available in the next release (version 4.3) of SQL# :-)

added clarification
Source Link
Solomon Rutzky
  • 69.5k
  • 8
  • 155
  • 300
  1. It's the wrong "type" of conversion. You are converting a string into a hex / binary representation of the characters them selves. For example, a "26" will become 0x3236 in hex as 0x32 is the same as doing CHAR(0x32) and 0x36 is the same as CHAR(0x36), or it can be referred to as the ASCII value of the number "2". What you want is to simply change the form of the string "26" (which represents a byte) into 0x26. And for that you need to use a style number of "2" for the CONVERT function. For example:

     SELECT CONVERT(VARBINARY(2), '26'), CONVERT(VARBINARY(2), '26', 2);
     -- 0x3236    0x26
    

This is why you are getting 0x323630303A383830303A366130363A32 from 2600:8800:6a06:2000:1d29:3b7:8c7c:271b. You are really only getting the first 16 characters from that string, which are: 2600:8800:6a06:2. The two characters on the left I explained directly above. The 3 characters on the right, 6:2 are the 0x363A32 on the right side of the hex value, since 0x36 = "6", 0x3A = ":", and 0x32 = "2".

  1. You will need to get rid of the colons as they are not valid binary digits. But the colons are there as delimiters for a reason: there are 8 segments, and if leading "0"s are removed, which is valid to do, then 0 really needs to be 0x0000, not 0x00 or 0x0. So, you need to ensure that each segment comes back as 4 hex digits.

    You will need to get rid of the colons as they are not valid binary digits. But the colons are there as delimiters for a reason: there are 8 segments, and if leading "0"s are removed, which is valid to do, then 0 really needs to be 0x0000, not 0x00 or 0x0. So, you need to ensure that each segment comes back as 4 hex digits.
  1. It's the wrong "type" of conversion. You are converting a string into a hex / binary representation of the characters them selves. For example, a "26" will become 0x3236 in hex as 0x32 is the same as doing CHAR(0x32) and 0x36 is the same as CHAR(0x36), or it can be referred to as the ASCII value of the number "2". What you want is to simply change the form of the string "26" (which represents a byte) into 0x26. And for that you need to use a style number of "2" for the CONVERT function. For example:

     SELECT CONVERT(VARBINARY(2), '26'), CONVERT(VARBINARY(2), '26', 2);
     -- 0x3236    0x26
    
  2. You will need to get rid of the colons as they are not valid binary digits. But the colons are there as delimiters for a reason: there are 8 segments, and if leading "0"s are removed, which is valid to do, then 0 really needs to be 0x0000, not 0x00 or 0x0. So, you need to ensure that each segment comes back as 4 hex digits.

  1. It's the wrong "type" of conversion. You are converting a string into a hex / binary representation of the characters them selves. For example, a "26" will become 0x3236 in hex as 0x32 is the same as doing CHAR(0x32) and 0x36 is the same as CHAR(0x36), or it can be referred to as the ASCII value of the number "2". What you want is to simply change the form of the string "26" (which represents a byte) into 0x26. And for that you need to use a style number of "2" for the CONVERT function. For example:

     SELECT CONVERT(VARBINARY(2), '26'), CONVERT(VARBINARY(2), '26', 2);
     -- 0x3236    0x26
    

This is why you are getting 0x323630303A383830303A366130363A32 from 2600:8800:6a06:2000:1d29:3b7:8c7c:271b. You are really only getting the first 16 characters from that string, which are: 2600:8800:6a06:2. The two characters on the left I explained directly above. The 3 characters on the right, 6:2 are the 0x363A32 on the right side of the hex value, since 0x36 = "6", 0x3A = ":", and 0x32 = "2".

  1. You will need to get rid of the colons as they are not valid binary digits. But the colons are there as delimiters for a reason: there are 8 segments, and if leading "0"s are removed, which is valid to do, then 0 really needs to be 0x0000, not 0x00 or 0x0. So, you need to ensure that each segment comes back as 4 hex digits.
added clarification
Source Link
Solomon Rutzky
  • 69.5k
  • 8
  • 155
  • 300
string    hex
2600      0x2600
0100      0x0100
0400      0x0400
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000
string    hex
2600      0x2600
0100      0x0100
0400      0x0400
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000

That was just a way to see what the pieces are. To put them together into a single hex value, you can do the following:

DECLARE @IPv6 VARBINARY(16) = 0x;

SELECT @IPv6 += CONVERT(BINARY(2), RIGHT('0000' + prt.[SplitVal], 4), 2)
FROM SQL#.String_Split4k('2600:100:400:0:0:0:0:0', ':', 1) prt;

SELECT @IPv6;
-- 0x26000100040000000000000000000000

You can create a function to handle this conversion. You can then store these VARBINARY(16) values and create an index on them, and then convert the string coming in and store that in a variable to use in the query.

Here is that same approach, but using the built-in STRING_SPLIT function:

DECLARE @IPv6 VARBINARY(16) = 0x;

SELECT @IPv6 += CONVERT(BINARY(2), RIGHT('0000' + prt.[SplitVal][value], 4), 2)
FROM SQL#.String_Split4kSTRING_SPLIT('2600:100:400:0:0:0:0:0', ':', 1) prt;

SELECT @IPv6;
-- 0x26000100040000000000000000000000

You can create a functionJust keep in mind that some folks are hesitant to handle this conversion. You can then store theseuse VARBINARY(16)STRING_SPLIT values and create an index on them, and then convertin this type of situation because here the string comingorder that the split parts are returned is important as it can change the value if they came back in a different order, and storethe built-in function doesn't return a row number. I personally don't see how the returned values could come back out of order, but that inis just an educated guess and not a variable toguarantee. If you want a guarantee, then don't use in the querySTRING_SPLIT built-in function.

string    hex
2600      0x2600
0100      0x0100
0400      0x0400
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000

That was just a way to see what the pieces are. To put them together into a single hex value, you can do the following:

DECLARE @IPv6 VARBINARY(16) = 0x;

SELECT @IPv6 += CONVERT(BINARY(2), RIGHT('0000' + prt.[SplitVal], 4), 2)
FROM SQL#.String_Split4k('2600:100:400:0:0:0:0:0', ':', 1) prt;

SELECT @IPv6;
-- 0x26000100040000000000000000000000

You can create a function to handle this conversion. You can then store these VARBINARY(16) values and create an index on them, and then convert the string coming in and store that in a variable to use in the query.

string    hex
2600      0x2600
0100      0x0100
0400      0x0400
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000
0000      0x0000

That was just a way to see what the pieces are. To put them together into a single hex value, you can do the following:

DECLARE @IPv6 VARBINARY(16) = 0x;

SELECT @IPv6 += CONVERT(BINARY(2), RIGHT('0000' + prt.[SplitVal], 4), 2)
FROM SQL#.String_Split4k('2600:100:400:0:0:0:0:0', ':', 1) prt;

SELECT @IPv6;
-- 0x26000100040000000000000000000000

You can create a function to handle this conversion. You can then store these VARBINARY(16) values and create an index on them, and then convert the string coming in and store that in a variable to use in the query.

Here is that same approach, but using the built-in STRING_SPLIT function:

DECLARE @IPv6 VARBINARY(16) = 0x;

SELECT @IPv6 += CONVERT(BINARY(2), RIGHT('0000' + prt.[value], 4), 2)
FROM STRING_SPLIT('2600:100:400:0:0:0:0:0', ':') prt;

SELECT @IPv6;
-- 0x26000100040000000000000000000000

Just keep in mind that some folks are hesitant to use STRING_SPLIT in this type of situation because here the order that the split parts are returned is important as it can change the value if they came back in a different order, and the built-in function doesn't return a row number. I personally don't see how the returned values could come back out of order, but that is just an educated guess and not a guarantee. If you want a guarantee, then don't use the STRING_SPLIT built-in function.

Source Link
Solomon Rutzky
  • 69.5k
  • 8
  • 155
  • 300
Loading