1

我正在使用 SQL 2005。我希望有人可以帮助我修改此语句,以便它可以处理多个连续的零部分。此语句将 IPv6 地址转换为二进制。

假设您有这个 IPv6 地址:2001:db8:85a3:0000:0000:8a2e:370:7334。

可以将其重写为 2001:db8:85a3::8a2e:370:7334 以消除连续的零部分。

但是,下面的 SQL 语句只能处理上面的 IPv6 地址,如果它用完整的符号写成 2001:db8:85a3:0000:0000:8a2e:370:7334,给我一个二进制结果 0x20010DB885A3000000008A2E03707334。

如何修改以下语句,以便我可以处理写为 2001:db8:85a3::8a2e:370:7334 的 IPv6 地址?甚至是 ::1 之类的地址?

DECLARE    @ipstr VARCHAR(50)
SET        @ipstr = '2001:db8:85a3::0000:8a2e:370:7334'
SELECT     CAST('' AS XML).value('xs:hexBinary( sql:column("y.ips") )', 'varbinary(16)')
FROM       (
            SELECT ips = (
                          SELECT  RIGHT('0000' + SUBSTRING(ips, NUMBER, CHARINDEX(':', ips, NUMBER) - NUMBER), 4)
                          FROM    master.dbo.spt_values
                                 ,(SELECT ips = ':' + @ipstr + ':') x
                          WHERE   TYPE = 'P'
                                  AND NUMBER BETWEEN 2 AND LEN(ips)
                                  AND SUBSTRING(ips, NUMBER-1, 1) = ':'
                          FOR     XML PATH('')
                         )
           ) y
4

2 回答 2

1

This probably isn't the cleanest solution, but it works:

WITH cteRawSections (RowNumber, ips) As
(
   -- Split the address into sections:
   SELECT
      ROW_NUMBER() OVER (ORDER BY number),
      Substring(ips, number, CharIndex(':', ips, number) - number)
   FROM
      master.dbo.spt_values
      CROSS APPLY
      (SELECT ips = ':' + @ipstr + ':') As c
   WHERE
      type = 'P'
   And
      number Between 2 And Len(ips)
   And
      Substring(ips, number - 1, 1) = ':'
),
cteSections (RowNumber, ips) As
(
   -- Pad the non-empty sections:
   SELECT
      RowNumber,
      Right('0000' + ips, 4)
   FROM
      cteRawSections
   WHERE
      ips != ''

   UNION ALL

   -- Include the missing sections:
   SELECT
      (SELECT Min(RowNumber) FROM cteRawSections WHERE ips = ''),
      '0000'
   FROM
      master.dbo.spt_values
   WHERE
      type = 'P'
   And
      number >= 1
   And
      number <= (SELECT 8 - Count(1) FROM cteRawSections WHERE ips != '')
),
cteJoined As
(
   -- Join the sections in order:
   SELECT ips = 
   (
      SELECT ips
      FROM cteSections
      ORDER BY RowNumber
      FOR XML PATH(''), TYPE
   ).value('.', 'varchar(max)')
)
SELECT
   CAST('' As XML).value('xs:hexBinary(sql:column("y.ips"))', 'varbinary(16)')
FROM
   cteJoined As y
;

http://www.sqlfiddle.com/#!3/d41d8/7258/0

NB: Your sample address, 2001:db8:85a3:0000:0000:0000:8a2e:370:7334, is too long to be a valid IPv6 address.

于 2012-12-17T19:21:34.317 回答
0

在 Set @ipstr 语句之后插入:

    declare @colonCount int = len(@ipstr)-len(replace(@ipstr,':',''))
    if(@colonCount<7)
        set @ipstr=replace(@ipstr,'::', replicate( ':0',7-@colonCount+1) +':')
于 2014-03-05T04:38:06.697 回答