慕尼黑8549860
存储IPv4的技术上正确的方法是二进制(4),因为它实际上是它(不,甚至不是INT32 / INT(4),我们都知道和喜欢的数字文本形式(255.255.255.255)只是其二进制内容的显示转换)。如果你这样做,你会希望函数转换为文本显示格式:以下是将文本显示形式转换为二进制的方法:CREATE FUNCTION dbo.fnBinaryIPv4(@ip AS VARCHAR(15)) RETURNS BINARY(4)ASBEGIN 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 @binENDgo以下是如何将二进制文件转换回文本显示形式:CREATE FUNCTION dbo.fnDisplayIPv4(@ip AS BINARY(4)) RETURNS VARCHAR(15)ASBEGIN 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 @strEND;go这是一个如何使用它们的演示:SELECT dbo.fnBinaryIPv4('192.65.68.201')--should return 0xC04144C9goSELECT dbo.fnDisplayIPv4( 0xC04144C9 )-- should return '192.65.68.201'go最后,在进行查找和比较时,如果希望能够利用索引,请始终使用二进制形式。更新:我想补充一种方法来解决SQL Server中标量UDF的固有性能问题,但仍然保留函数的代码重用是使用iTVF(内联表值函数)。以下是如何将上面的第一个函数(字符串到二进制)重写为iTVF:CREATE FUNCTION dbo.itvfBinaryIPv4(@ip AS VARCHAR(15)) RETURNS TABLEAS 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 0xC04144C9go以下是如何在INSERT中使用它INSERT INTo myIpTableSELECT {other_column_values,...}, (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))
陪伴而非守候
以下是将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) ASBEGINDECLARE @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 ENDSET @ipAddress = @ipAddress + @delimWHILE @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 @bytesEND-- SELECT dbo.fn_ConvertBinaryToIpAddress(0x200201FF06C200000000000001FF06C2)-- SELECT dbo.fn_ConvertBinaryToIpAddress(0x0000000000000000000000000A0118FF)ALTER FUNCTION [dbo].[fn_ConvertBinaryToIpAddress]( @bytes BINARY(16))RETURNS VARCHAR(39) ASBEGINDECLARE @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' ENDELSE 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 ENDRETURN @ipAddress END