Tipo de datos para almacenar direcciones IP en SQL Server

Respuestas:

130

La forma técnicamente correcta de almacenar IPv4 es binaria (4), ya que eso es lo que realmente es (no, ni siquiera INT32 / INT (4), la forma textual numérica que todos conocemos y amamos (255.255.255.255) es simplemente la conversión de visualización de su contenido binario).

Si lo hace de esta manera, querrá que las funciones se conviertan hacia y desde el formato de visualización textual:

A continuación, se explica cómo convertir la forma de visualización textual en binario:

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

Y aquí se explica cómo convertir el binario nuevamente al formato de visualización textual:

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

Aquí hay una demostración de cómo usarlos:

SELECT dbo.fnBinaryIPv4('192.65.68.201')
--should return 0xC04144C9
go

SELECT dbo.fnDisplayIPv4( 0xC04144C9 )
-- should return '192.65.68.201'
go

Por último, cuando realice búsquedas y comparaciones, utilice siempre la forma binaria si desea poder aprovechar sus índices.


ACTUALIZAR:

Quería agregar esa forma de abordar los problemas de rendimiento inherentes de las UDF escalares en SQL Server, pero aún así conservar el código: la reutilización de una función es usar una iTVF (función con valores de tabla en línea) en su lugar. Así es como la primera función anterior (cadena a binario) se puede reescribir como un 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

Aquí está en el ejemplo:

SELECT bin FROM dbo.fnBinaryIPv4('192.65.68.201')
--should return 0xC04144C9
go

Y así es como lo usaría en un INSERT

INSERT INTo myIpTable
SELECT {other_column_values,...},
       (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))
RBarryYoung
fuente
33
Creo que esto solo es correcto en un sentido académico. Sin conocer el propósito y el problema de dominio que el autor intenta resolver, sospecho que esto complicará innecesariamente la interacción con los datos y potencialmente degradará el rendimiento.
Eric Sabine
21
IPv4 es una secuencia ordenada de cuatro bytes. Eso ES su dominio, y en formato de almacenamiento es un BIN (4). El formato de almacenamiento no interferirá con el rendimiento porque es el formato óptimo. La función de conversión podría (porque udf apesta en el servidor SQL), que puede resolverse ya sea en línea o haciendo la conversión en el cliente. Finalmente, este enfoque tiene la ventaja significativa de que puede buscar direcciones en subredes de Clase 1, 2 o 3 mediante escaneos de rango indexado (DONDE ip ENTRE fnBinaryIPv4 ('132.31.55.00') Y fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung
1
@RBarryYoung Lo almacenaría como un número entero. ¿Podría explicar cuál es la ventaja de rendimiento de almacenarlo como binario?
Pacerier
3
@Pacerier: 1) vea el comentario anterior para ver un ejemplo, y 2) No afirmé que Binary sería más rápido que Integer. Afirmé que A) es el formato correcto (y lo es), y B) no sería más lento.
RBarryYoung
1
Sí, estás equivocado, eso no es lo que dice Dan. Además, este no es un foro de discusión y no es adecuado para él. Stackoverflow es una sección de preguntas y respuestas, si tiene alguna pregunta, publíquela.
RBarryYoung
23

Puede usar varchar. La longitud de IPv4 es estática, pero la de IPv6 puede ser muy variable.

A menos que tenga una buena razón para almacenarlo como binario, quédese con un tipo de cadena (textual).

NDC
fuente
39
La longitud de IPv6 es muy fija: 128 bits.
Broam
4
A menos que esté hablando de datos que un humano nunca leerá o de una gran cantidad de datos, esta es la mejor respuesta.
Aren Cambre
10
Una razón simple para usar binarios y no cadenas: ¡la versión binaria permite verificar el rango numérico de las direcciones IP! La versión de texto no lo hace. Por supuesto, esto depende del uso requerido, pero los números binarios son más útiles ya que tienen un significado real.
Gone Coding
4
varchar ocupa mucho más espacio en la base de datos. Una dirección IPv4 de 32 bits necesita 4 bytes para almacenar numéricamente, y una dirección IPv6 de 128 bits necesita 16 bytes para almacenar numéricamente. Mientras tanto, esa dirección IPv4 necesita 15 bytes para almacenar como una cadena y una dirección IPv6 podría tomar hasta 39 bytes como una cadena.
Aaron Schultz
1
varbinary (16) es el camino a seguir
jjxtra
17

Aquí hay un código para convertir IPV4 o IPv6 en formato varchar a binario (16) y viceversa. Esta es la forma más pequeña que se me ocurre. Debería indexar bien y proporcionar una forma relativamente fácil de filtrar en subredes. Requiere SQL Server 2005 o posterior. No estoy seguro de que sea totalmente a prueba de balas. Espero que esto ayude.

-- 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 
Jerry Birchler
fuente
Esta respuesta funcionó perfectamente para la base de datos db-ip IP to country. Una conversión de ida y vuelta mostró solo diferencias menores en las que los 0 se recortaron de ipv6 (inicial y siguiente).
crokusek
1
En ToBinary (), encuentre algunos problemas con el plan de consulta y el uso de fn_varbintohexstr () que no está marcado como determinista. ¿Qué tal el otro? sección: seleccione @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Parece equivalente. ¿No necesita un motor @ zone o xml? Parece una buena aceleración si el motor xml se eliminó de alguna manera de ':' también.
crokusek
concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) convertirá un largo sin firmar que contenga una dirección IP en un forma legible por humanos.
theking2
@ theking2 - esto no se aplica a SQL Server ya que >> no es compatible
Alex
Tenga en cuenta que hay un error en fn_ConvertIpAddressToBinary. Vea la respuesta de C.Plock y la mía .
Alex
10

Como quiero manejar ambos IPv4y IPv6, estoy usando VARBINARY(16)y las siguientes SQL CLRfunciones para convertir la textpresentación de la dirección IP a bytes y al revés:

[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlBytes GetIPAddressBytesFromString (SqlString value)
{
    IPAddress IP;

    if (IPAddress.TryParse(value.Value, out IP))
    {
        return new SqlBytes(IP.GetAddressBytes());
    }
    else
    {
        return new SqlBytes();
    }
}


[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlString GetIPAddressStringFromBytes(SqlBytes value)
{
    string output;

    if (value.IsNull)
    {
        output = "";
    }
    else
    {
        IPAddress IP = new IPAddress(value.Value);
        output = IP.ToString();
    }

    return new SqlString(output);
}
gotqn
fuente
8

Las personas que usan .NET pueden usar la clase IPAddress para analizar la cadena IPv4 / IPv6 y almacenarla como VARBINARY(16). Puede usar la misma clase para convertir byte[]a cadena. Si desea convertir el VARBINARYen SQL:

--SELECT 
--  dbo.varbinaryToIpString(CAST(0x7F000001 AS VARBINARY(4))) IPv4,
--  dbo.varbinaryToIpString(CAST(0x20010DB885A3000000008A2E03707334 AS VARBINARY(16))) IPv6

--ALTER 
CREATE
FUNCTION dbo.varbinaryToIpString
(
    @varbinaryValue VARBINARY(16)
)
RETURNS VARCHAR(39)
AS
BEGIN
    IF @varbinaryValue IS NULL
        RETURN NULL
    IF DATALENGTH(@varbinaryValue) = 4
    BEGIN
        RETURN 
            CONVERT(VARCHAR(3), CONVERT(INT, SUBSTRING(@varbinaryValue, 1, 1))) + '.' +
            CONVERT(VARCHAR(3), CONVERT(INT, SUBSTRING(@varbinaryValue, 2, 1))) + '.' +
            CONVERT(VARCHAR(3), CONVERT(INT, SUBSTRING(@varbinaryValue, 3, 1))) + '.' +
            CONVERT(VARCHAR(3), CONVERT(INT, SUBSTRING(@varbinaryValue, 4, 1)))
    END
    IF DATALENGTH(@varbinaryValue) = 16
    BEGIN
        RETURN 
            sys.fn_varbintohexsubstring(0, @varbinaryValue,  1, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue,  3, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue,  5, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue,  7, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue,  9, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue, 11, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue, 13, 2) + ':' +
            sys.fn_varbintohexsubstring(0, @varbinaryValue, 15, 2)
    END

    RETURN 'Invalid'
END
M. Turnhout
fuente
7

sys.dm_exec_connectionsusa varchar (48) después de SQL Server 2005 SP1. Suena bastante bien para mí, especialmente si quieres usarlo en comparación con tu valor.

Siendo realistas, todavía no verá IPv6 como la corriente principal por un tiempo, por lo que prefiero la ruta 4 tinyint. Dicho esto, estoy usando varchar (48) porque tengo que usar sys.dm_exec_connections...

De otra manera. La respuesta de Mark Redman menciona una pregunta de debate de SO anterior .

gbn
fuente
4
siendo realistas, a estar viendo IPv6
Pacerier
10
Siendo realistas, todavía no veremos el año 2000 por un tiempo, también podemos usar fechas de 2 dígitos para ahorrar algunos bytes. Oh espera.
Eric J.
1

Gracias RBarry. Estoy armando un sistema de asignación de bloques de IP y almacenar como binario es el único camino a seguir.

Estoy almacenando la representación CIDR (por ejemplo, 192.168.1.0/24) del bloque de IP en un campo varchar, y estoy usando 2 campos calculados para contener la forma binaria del inicio y el final del bloque. A partir de ahí, puedo ejecutar consultas rápidas para ver si un bloque dado ya ha sido asignado o es libre de asignar.

Modifiqué su función para calcular la dirección IP final así:

CREATE FUNCTION dbo.fnDisplayIPv4End(@block AS VARCHAR(18)) RETURNS BINARY(4)
AS
BEGIN
    DECLARE @bin AS BINARY(4)
    DECLARE @ip AS VARCHAR(15)
    DECLARE @size AS INT

    SELECT @ip = Left(@block, Len(@block)-3)
    SELECT @size = Right(@block, 2)

    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))

    SELECT @bin = CAST(@bin + POWER(2, 32-@size) AS BINARY(4))
    RETURN @bin
END;
go
rawk
fuente
1

Por lo general, uso un filtro VARCHAR simple y simple para una dirección IP que funciona bien.

Si desea filtrar por rangos de direcciones IP, lo dividiría en cuatro números enteros.

Daniel Elliott
fuente
1
¿Qué es un rango? No todas las subredes tienen 8 bytes. ¿Cuál es el rango de direcciones IP para la red en la que se encuentra este host: 50.50.50.50/20?
Bradley Kreider
2
Los enteros son demasiado grandes para almacenar un valor de 0-255. En su lugar, utilice un diminuto.
SandRock
0

Me gustan las funciones de SandRock. Pero encontré un error en el código de dbo.fn_ConvertIpAddressToBinary . El parámetro entrante de @ipAddress VARCHAR (39) es demasiado pequeño cuando le concatena el @delim.

SET @ipAddress = @ipAddress + @delim

Puede aumentarlo a 40. O mejor aún, use una nueva variable que sea más grande y úsela internamente. De esa manera no perderá el último par en números grandes.

SELECT dbo.fn_ConvertIpAddressToBinary('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
C.Plock
fuente
De hecho, hay un error
Alex
0

La siguiente respuesta se basa en las respuestas de M. Turnhout y Jerry Birchler a esta pregunta, pero con las siguientes mejoras:

  • Reemplazado el uso de funciones no documentadas ( sys.fn_varbintohexsubstring, fn_varbintohexstr) con CONVERT()por estilos binarios
  • Reemplazados XML "hacks" ( CAST('' as xml).value('xs:hexBinary())) con CONVERT()por estilos binarios
  • Se corrigió un error en la implementación de Jerry Birchler de fn_ConvertIpAddressToBinary(como lo señaló C.Plock )
  • Agregar azúcar de sintaxis menor

El código se ha probado en SQL Server 2014 y SQL Server 2016 (consulte los casos de prueba al final)

IPAddressVarbinaryToString

Convierte valores de 4 bytes en IPV4 y valores de 16 bytes en representaciones de cadenas IPV6 . Tenga en cuenta que esta función no acorta las direcciones.

ALTER FUNCTION dbo.IPAddressVarbinaryToString
(
    @varbinaryValue VARBINARY( 16 )
)
RETURNS VARCHAR(39)
AS
BEGIN
    IF @varbinaryValue IS NULL
        RETURN NULL;
    ELSE IF DATALENGTH( @varbinaryValue ) = 4
        RETURN 
            CONVERT( VARCHAR(3), CONVERT(TINYINT, SUBSTRING( @varbinaryValue, 1, 1 ))) + '.' +
            CONVERT( VARCHAR(3), CONVERT(TINYINT, SUBSTRING( @varbinaryValue, 2, 1 ))) + '.' +
            CONVERT( VARCHAR(3), CONVERT(TINYINT, SUBSTRING( @varbinaryValue, 3, 1 ))) + '.' +
            CONVERT( VARCHAR(3), CONVERT(TINYINT, SUBSTRING( @varbinaryValue, 4, 1 )));
    ELSE IF DATALENGTH( @varbinaryValue ) = 16
        RETURN 
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue,  1, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue,  3, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue,  5, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue,  7, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue,  9, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue, 11, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue, 13, 2 ), 2 ) + ':' +
            CONVERT( VARCHAR(4), SUBSTRING( @varbinaryValue, 15, 2 ), 2 );

    RETURN 'Invalid';
END

Casos de prueba:

SELECT dbo.IPAddressVarbinaryToString(0x00000000000000000000000000000000) -- 0000:0000:0000:0000:0000:0000:0000:0000 (no address shortening)
SELECT dbo.IPAddressVarbinaryToString(0x00010002000300400500060070000089) -- 0001:0002:0003:0040:0500:0600:7000:0089
SELECT dbo.IPAddressVarbinaryToString(0xC0A80148) -- 255.168.1.72
SELECT dbo.IPAddressVarbinaryToString(0x7F000001) -- 127.0.0.1 (no address shortening)
SELECT dbo.IPAddressVarbinaryToString(NULL) -- NULL

IPAddressStringToVarbinary

Convierte representaciones de cadenas de IPV4 e IPV6 en valores binarios de 4 bytes y 16 bytes respectivamente. Tenga en cuenta que esta función puede analizar la mayoría (todas las de uso común) de las representaciones de direcciones abreviadas (por ejemplo, 127 ... 1 y 2001: db8 :: 1319: 370: 7348). Para forzar que la función Thins siempre devuelva valores binarios de 16 bytes, elimine el comentario de la concatenación de ceros iniciales al final de la función.

ALTER FUNCTION [dbo].[IPAddressStringToVarbinary]
(
    @IPAddress VARCHAR( 39 )
)
RETURNS VARBINARY(16) AS
BEGIN

IF @ipAddress IS NULL
    RETURN NULL;

DECLARE @bytes VARBINARY(16), @token VARCHAR(4),
    @vbytes VARBINARY(16) = 0x, @vbzone VARBINARY(2),
    @tIPAddress VARCHAR( 40 ),
    @colIndex TINYINT,
    @delim CHAR(1) = '.',
    @prevColIndex TINYINT = 0,
    @parts TINYINT = 0, @limit TINYINT = 4;

-- Get position if IPV4 delimiter
SET @colIndex = CHARINDEX( @delim, @ipAddress );

-- If not IPV4, then assume IPV6
IF @colIndex = 0
BEGIN
    SELECT @delim = ':', @limit = 8, @colIndex = CHARINDEX( @delim, @ipAddress );

    -- Get number of parts (delimiters)
    WHILE @colIndex > 0
        SELECT @parts += 1, @colIndex = CHARINDEX( @delim, @ipAddress, @colIndex + 1 );

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

    IF @colIndex = 0
        RETURN NULL;
END

-- Add trailing delimiter (need new variable of larger size)
SET @tIPAddress = @IPAddress + @delim;

WHILE @colIndex > 0
BEGIN
    SET @token = SUBSTRING( @tIPAddress, @prevColIndex + 1, @Colindex - @prevColIndex - 1 );

    IF @delim = ':'
    BEGIN
        SELECT @vbzone = CONVERT( VARBINARY(2), RIGHT( '0000' + @token, 4 ), 2 ), @vbytes += @vbzone;

        -- Handles consecutive sections of zeros representation rule (i.e. ::)(https://en.wikipedia.org/wiki/IPv6#Address_representation)
        IF @token = ''
            WHILE @parts + 1 < @limit
                SELECT @vbytes += @vbzone, @parts += 1;
    END
    ELSE
    BEGIN
        SELECT @vbzone = CONVERT( VARBINARY(1), CONVERT( TINYINT, @token )), @vbytes += @vbzone
    END

    SELECT @prevColIndex = @colIndex, @colIndex = CHARINDEX( @delim, @tIPAddress, @colIndex + 1 ) 
END

SET @bytes =
    CASE @delim
        WHEN ':' THEN @vbytes
        ELSE /*0x000000000000000000000000 +*/ @vbytes -- Return IPV4 addresses as 4 byte binary (uncomment leading 0s section to force 16 byte binary)
    END 

RETURN @bytes

END

Casos de prueba

Casos válidos

SELECT dbo.IPAddressStringToVarbinary( '0000:0000:0000:0000:0000:0000:0000:0001' ) -- 0x0000000000000000000000000001 (check bug fix)
SELECT dbo.IPAddressStringToVarbinary( '0001:0002:0003:0040:0500:0600:7000:0089' ) -- 0x00010002000300400500060070000089
SELECT dbo.IPAddressStringToVarbinary( '2001:db8:85a3:8d3:1319::370:7348' )     -- 0x20010DB885A308D31319000003707348 (check short hand)
SELECT dbo.IPAddressStringToVarbinary( '2001:db8:85a3:8d3:1319:0000:370:7348' ) -- 0x20010DB885A308D31319000003707348
SELECT dbo.IPAddressStringToVarbinary( '192.168.1.72' ) -- 0xC0A80148
SELECT dbo.IPAddressStringToVarbinary( '127...1' ) -- 0x7F000001 (check short hand)
SELECT dbo.IPAddressStringToVarbinary( NULL ) -- NULL
SELECT dbo.IPAddressStringToVarbinary( '' ) -- NULL
-- Check that conversions return original address
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '0001:0002:0003:0040:0500:0600:7000:0089' )) -- '0001:0002:0003:0040:0500:0600:7000:0089' 
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '127...1' )) -- 127.0.0.1
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '192.168.1.72' )) -- 192.168.1.72
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '2001:db8:85a3:8d3:1319::370:7348' ))     -- 2001:0db8:85a3:08d3:1319:0000:0370:7348
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '2001:db8:85a3:8d3:1314:0000:370:7348' )) -- 2001:0db8:85a3:08d3:1319:0000:0370:7348
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '2001:db8:85a3:8d3::370:7348' )) -- 2001:0DB8:85A3:08D3:0000:0000:0370:7348
-- This is technically an invalid IPV6 (according to Wikipedia) but it parses correctly
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '2001:db8::1319::370:7348' )) -- 2001:0DB8:0000:0000:1319:0000:0370:7348

Casos inválidos

SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '2001:db8::1319::7348' )) -- 2001:0DB8:0000:0000:0000:1319:0000:7348 (ambiguous address)
SELECT dbo.IPAddressStringToVarbinary( '127.1' ) -- 127.0.0.1 (not supported short-hand)
SELECT dbo.IPAddressVarbinaryToString( dbo.IPAddressStringToVarbinary( '127.1' )) -- 127.0.0.1 (not supported short-hand)
SELECT dbo.IPAddressStringToVarbinary( '0300.0000.0002.0353' ) -- octal byte values
SELECT dbo.IPAddressStringToVarbinary( '0xC0.0x00.0x02.0xEB' ) -- hex values
SELECT dbo.IPAddressStringToVarbinary( 'C0.00.02.EB' ) -- hex values
Alex
fuente
-2

Estoy usando varchar(15)hasta ahora todo está funcionando para mí. Insertar, actualizar, seleccionar. Acabo de iniciar una aplicación que tiene direcciones IP, aunque todavía no he hecho mucho trabajo de desarrollo.

Aquí está la declaración de selección:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Profundo
fuente