为了账号安全,请及时绑定邮箱和手机立即绑定

用于在SQL Server中存储ip地址的数据类型

用于在SQL Server中存储ip地址的数据类型

慕侠2389804 2019-08-30 16:53:19
我应该选择什么数据类型在SQL Server中存储IP地址?通过选择正确的数据类型,可以很容易地按IP地址进行过滤吗?
查看完整描述

3 回答

?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

存储IPv4的技术上正确的方法是二进制(4),因为它实际上是它(不,甚至不是INT32 / INT(4),我们都知道和喜欢的数字文本形式(255.255.255.255)只是其二进制内容的显示转换)。


如果你这样做,你会希望函数转换为文本显示格式:


以下是将文本显示形式转换为二进制的方法:


CREATE FUNCTION dbo.fnBinaryIPv4(@ip AS VARCHAR(15)) RETURNS BINARY(4)

AS

BEGIN

    DECLARE @bin AS BINARY(4)


    SELECT @bin = CAST( CAST( PARSENAME( @ip, 4 ) AS INTEGER) AS BINARY(1))

                + CAST( CAST( PARSENAME( @ip, 3 ) AS INTEGER) AS BINARY(1))

                + CAST( CAST( PARSENAME( @ip, 2 ) AS INTEGER) AS BINARY(1))

                + CAST( CAST( PARSENAME( @ip, 1 ) AS INTEGER) AS BINARY(1))


    RETURN @bin

END

go

以下是如何将二进制文件转换回文本显示形式:


CREATE FUNCTION dbo.fnDisplayIPv4(@ip AS BINARY(4)) RETURNS VARCHAR(15)

AS

BEGIN

    DECLARE @str AS VARCHAR(15) 


    SELECT @str = CAST( CAST( SUBSTRING( @ip, 1, 1) AS INTEGER) AS VARCHAR(3) ) + '.'

                + CAST( CAST( SUBSTRING( @ip, 2, 1) AS INTEGER) AS VARCHAR(3) ) + '.'

                + CAST( CAST( SUBSTRING( @ip, 3, 1) AS INTEGER) AS VARCHAR(3) ) + '.'

                + CAST( CAST( SUBSTRING( @ip, 4, 1) AS INTEGER) AS VARCHAR(3) );


    RETURN @str

END;

go

这是一个如何使用它们的演示:


SELECT dbo.fnBinaryIPv4('192.65.68.201')

--should return 0xC04144C9

go


SELECT dbo.fnDisplayIPv4( 0xC04144C9 )

-- should return '192.65.68.201'

go

最后,在进行查找和比较时,如果希望能够利用索引,请始终使用二进制形式。


更新:


我想补充一种方法来解决SQL Server中标量UDF的固有性能问题,但仍然保留函数的代码重用是使用iTVF(内联表值函数)。以下是如何将上面的第一个函数(字符串到二进制)重写为iTVF:


CREATE FUNCTION dbo.itvfBinaryIPv4(@ip AS VARCHAR(15)) RETURNS TABLE

AS RETURN (

    SELECT CAST(

               CAST( CAST( PARSENAME( @ip, 4 ) AS INTEGER) AS BINARY(1))

            +  CAST( CAST( PARSENAME( @ip, 3 ) AS INTEGER) AS BINARY(1))

            +  CAST( CAST( PARSENAME( @ip, 2 ) AS INTEGER) AS BINARY(1))

            +  CAST( CAST( PARSENAME( @ip, 1 ) AS INTEGER) AS BINARY(1))

                AS BINARY(4)) As bin

        )

go

这是示例中的内容:


SELECT bin FROM dbo.fnBinaryIPv4('192.65.68.201')

--should return 0xC04144C9

go

以下是如何在INSERT中使用它


INSERT INTo myIpTable

SELECT {other_column_values,...},

       (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))


查看完整回答
反对 回复 2019-08-30
?
陪伴而非守候

TA贡献1757条经验 获得超8个赞

以下是将varchar格式的IPV4或IPv6转换为二进制(16)并返回的一些代码。这是我能想到的最小的形式。它应该很好地索引并提供一种相对简单的方法来过滤子网。需要SQL Server 2005或更高版本。不确定它是完全防弹的。希望这可以帮助。


-- SELECT dbo.fn_ConvertIpAddressToBinary('2002:1ff:6c2::1ff:6c2')

-- SELECT dbo.fn_ConvertIpAddressToBinary('10.4.46.2')

-- SELECT dbo.fn_ConvertIpAddressToBinary('bogus')


ALTER FUNCTION dbo.fn_ConvertIpAddressToBinary

(

     @ipAddress VARCHAR(39)

)

RETURNS BINARY(16) AS

BEGIN

DECLARE

     @bytes BINARY(16), @vbytes VARBINARY(16), @vbzone VARBINARY(2)

     , @colIndex TINYINT, @prevColIndex TINYINT, @parts TINYINT, @limit TINYINT

     , @delim CHAR(1), @token VARCHAR(4), @zone VARCHAR(4)


SELECT

     @delim = '.'

     , @prevColIndex = 0

     , @limit = 4

     , @vbytes = 0x

     , @parts = 0

     , @colIndex = CHARINDEX(@delim, @ipAddress)


IF @colIndex = 0

     BEGIN

           SELECT

                @delim = ':'

                , @limit = 8

                , @colIndex = CHARINDEX(@delim, @ipAddress)

           WHILE @colIndex > 0

                SELECT

                      @parts = @parts + 1

                      , @colIndex = CHARINDEX(@delim, @ipAddress, @colIndex + 1)

           SET @colIndex = CHARINDEX(@delim, @ipAddress)


           IF @colIndex = 0

                RETURN NULL     

     END


SET @ipAddress = @ipAddress + @delim


WHILE @colIndex > 0

     BEGIN

           SET @token = SUBSTRING(@ipAddress, @prevColIndex + 1, @Colindex - @prevColIndex - 1)


           IF @delim = ':'

                BEGIN

                      SET  @zone = RIGHT('0000' + @token, 4)


                      SELECT

                           @vbzone = CAST('' AS XML).value('xs:hexBinary(sql:variable("@zone"))', 'varbinary(2)')

                           , @vbytes = @vbytes + @vbzone


                      IF @token = ''

                           WHILE @parts + 1 < @limit

                                 SELECT

                                      @vbytes = @vbytes + @vbzone

                                      , @parts = @parts + 1

                END

           ELSE

                BEGIN

                      SET @zone = SUBSTRING('' + master.sys.fn_varbintohexstr(CAST(@token AS TINYINT)), 3, 2)


                      SELECT

                           @vbzone = CAST('' AS XML).value('xs:hexBinary(sql:variable("@zone"))', 'varbinary(1)')

                           , @vbytes = @vbytes + @vbzone

                END


           SELECT

                @prevColIndex = @colIndex

                , @colIndex = CHARINDEX(@delim, @ipAddress, @colIndex + 1) 

     END            


SET @bytes =

     CASE @delim

           WHEN ':' THEN @vbytes

           ELSE 0x000000000000000000000000 + @vbytes

     END 


RETURN @bytes


END

-- SELECT dbo.fn_ConvertBinaryToIpAddress(0x200201FF06C200000000000001FF06C2)

-- SELECT dbo.fn_ConvertBinaryToIpAddress(0x0000000000000000000000000A0118FF)


ALTER FUNCTION [dbo].[fn_ConvertBinaryToIpAddress]

(

     @bytes BINARY(16)

)

RETURNS VARCHAR(39) AS

BEGIN

DECLARE

     @part VARBINARY(2)

     , @colIndex TINYINT

     , @ipAddress VARCHAR(39)


SET @ipAddress = ''


IF SUBSTRING(@bytes, 1, 12) = 0x000000000000000000000000

     BEGIN

           SET @colIndex = 13

           WHILE @colIndex <= 16

                SELECT

                      @part = SUBSTRING(@bytes, @colIndex, 1)

                      , @ipAddress = @ipAddress

                           + CAST(CAST(@part AS TINYINT) AS VARCHAR(3))

                           + CASE @colIndex WHEN 16 THEN '' ELSE '.' END

                      , @colIndex = @colIndex + 1


           IF @ipAddress = '0.0.0.1'

                SET @ipAddress = '::1'

     END

ELSE

     BEGIN

           SET @colIndex = 1

           WHILE @colIndex <= 16

                BEGIN

                      SET @part = SUBSTRING(@bytes, @colIndex, 2)

                      SELECT

                           @ipAddress = @ipAddress

                                 + CAST('' as xml).value('xs:hexBinary(sql:variable("@part") )', 'varchar(4)')

                                 + CASE @colIndex WHEN 15 THEN '' ELSE ':' END

                           , @colIndex = @colIndex + 2

                END

     END


RETURN @ipAddress   


END 


查看完整回答
反对 回复 2019-08-30
  • 3 回答
  • 0 关注
  • 985 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信