Transportación de MySql a T-Sql. ¿Algún INET_ATON () equivalente?

Necesita mover algún código de MySql a TSql. Tengo un par de llamadas a INET_ATON que convierte una cadena que se parece a una IPAddress en un número. ¿Hay un equivalente de T-SQL?

Un abuso de la function parsname:

create function INET_ATON (@addr varchar(15)) returns bigint with schemabinding as begin return cast(parsename(@addr, 4) as bigint) * 16777216 + cast(parsename(@addr, 3) as bigint) * 65536 + cast(parsename(@addr, 2) as bigint) * 256 + cast(parsename(@addr, 1) as bigint) end 

Sin embargo, esa cosa de "dirección de forma corta" no se admite aquí.

Aquí hay una function para convertir una dirección IP en una cadena:

 CREATE FUNCTION dbo.IpToString (@ip_str VarChar(15)) returns BigInt as begin declare @i int declare @dot_pos int declare @current_part VarChar(15) declare @result BigInt set @result = 0 set @i = 0 while Len(@ip_str) > 0 begin set @i = @i + 1 set @dot_pos = CharIndex('.', @ip_str) if @dot_pos > 0 begin set @current_part = Left(@ip_str, @dot_pos - 1) set @ip_str = SubString(@ip_str, @dot_pos + 1, 15) end else begin set @current_part = @ip_str set @ip_str = '' end if Len(@current_part) > 3 Return(Null) if IsNumeric(@current_part) = 0 Return (Null) if not cast(@current_part as int) between 0 and 255 Return (Null) set @result = 256 * @result + Cast(@current_part as BigInt) end if @i = 4 Return(@result) Return(Null) end 

Después de crear la function, puedes llamarla así:

 select dbo.IpToString('1.2.3.4') 

Poco mejor. Utiliza int (4b) en lugar de bigint (8b). Su resultado solo debe ser de cuatro bytes … uno por octeto:

 create function INET_ATON (@ip varchar(15)) returns int begin declare @rslt int -- This first part is a little error checking -- Looks for three dots and all numbers when not dots if len(@ip) - len(replace(@ip,'.','')) = 3 AND isnumeric(replace(@ip,'.','')) = 1 begin set @rslt = convert(int, convert(binary(1),convert(tinyint,parsename(@ip, 4))) + convert(binary(1),convert(tinyint,parsename(@ip, 3))) + convert(binary(1),convert(tinyint,parsename(@ip, 2))) + convert(binary(1),convert(tinyint,parsename(@ip, 1))) ) end else set @rslt = 0 return @rslt end; 

Dos pequeñas mejoras

  1. Escrito como una function en línea con valores de tabla
  2. Funciona en torno al hecho de que PARSENAME no es determinista

Función:

 CREATE FUNCTION dbo.IPv4ToInt ( @ip varchar(15) ) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT IPv4Int = CASE WHEN LEN(@ip) - LEN(REPLACE(@ip COLLATE Latin1_General_BIN2, '.', '')) = 3 AND @ip COLLATE Latin1_General_BIN2 NOT LIKE '%[^.0-9]%' AND @ip COLLATE Latin1_General_BIN2 LIKE '[0-9]%.[0-9]%.[0-9]%.[0-9]%' THEN CONVERT ( integer, ( CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) - 1))) + CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) - 1))) + CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1)) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) - 1))) + CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1)) + 1, LEN(@ip) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1))))) ) ) ELSE NULL END; 

Mostrar las properties de la function:

 SELECT IsDeterministic = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsDeterministic'), IsSystemVerified = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsSystemVerified'), IsPrecise = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsPrecise'); 

Ejemplo de uso:

 DECLARE @Data TABLE ( IPv4 varchar(15) NULL ); INSERT @Data (IPv4) VALUES ('192.168.0.3'), ('0.0.0.0'), ('10.0.16.129'), ('255.255.255.255'); SELECT * FROM @Data AS d CROSS APPLY dbo.IPv4ToInt(d.IPv4) AS ipti; 

Más una opción diferente que una respuesta directa a su pregunta (veo que los votos a favor van a llegar ^^), pero también podría considerar poner la lógica de conversión en su software en lugar de la consulta. Dependiendo del idioma y el caso de uso, esto podría ser incluso mejor.

Ejemplos

PHP : ip2long("192.168.1.1");

C / C ++ : inet_addr("192.168.1.1");

DO#

 System.Net.IPAddress ip; long ipn = (System.Net.IPAddress.TryParse("192.168.1.1", out ip)) ? (((long) ip.GetAddressBytes()[0] << 24) | (ip.GetAddressBytes()[1] << 16) | (ip.GetAddressBytes()[2] << 8) | ip.GetAddressBytes()[3]) : 0; 

También podría darle -1 , o null (con long? Como tipo de datos), o escribir un método que arroje una exception, en caso de que la conversión falle.

Pitón

 networkinguce(lambda sum, chunk: sum <<8 | chunk, map(int, '192.168.1.1'.split("."))) 

Antes de comenzar el downvoting: esto es solo un pequeño ejemplo, aquí no se maneja ningún error, lo sé.

Conclusión

Por supuesto, la mayor parte del time es mejor dejar que el DB realice su trabajo, pero realmente depende, y en caso de que no tenga un proyecto con millones de requestes por segundo, esto podría ayudar.