Tipo de dados para armazenar o endereço IP no SQL Server

Respostas:

130

A forma tecnicamente correta de armazenar IPv4 é binária (4), já que é o que realmente é (não, nem mesmo um INT32 / INT (4), a forma textual numérica que todos nós conhecemos e amamos (255.255.255.255) sendo justa a conversão de exibição de seu conteúdo binário).

Se você fizer isso dessa forma, desejará que as funções sejam convertidas de e para o formato de exibição textual:

Veja como converter a forma de exibição textual em binária:

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

E aqui está como converter o binário de volta para a forma de exibição 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

Aqui está uma demonstração de como usá-los:

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

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

Finalmente, ao fazer pesquisas e comparações, sempre use a forma binária se quiser poder alavancar seus índices.


ATUALIZAR:

Eu queria adicionar que uma maneira de resolver os problemas de desempenho inerentes de UDFs escalares no SQL Server, mas ainda manter a reutilização de código de uma função, é usar um iTVF (função com valor de tabela embutida). Veja como a primeira função acima (string para binário) pode ser reescrita como um 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

Aqui está o exemplo:

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

E aqui está como você o usaria em um INSERT

INSERT INTo myIpTable
SELECT {other_column_values,...},
       (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))
RBarryYoung
fonte
33
Acho que isso é correto apenas no sentido acadêmico. Sem saber o propósito e o problema de domínio que o autor do pôster está tentando resolver, suspeito que isso complicará desnecessariamente a interação com os dados e poderá degradar o desempenho.
Eric Sabine
21
IPv4 é uma sequência ordenada de quatro bytes. Isso é seu domínio e em formato de armazenamento é um BIN (4). O formato de armazenamento não interfere no desempenho porque é o formato ideal. A função de conversão pode (porque o udf é péssimo no servidor SQL), o que pode ser resolvido tanto em linha quanto fazendo a conversão no cliente. Finalmente, esta abordagem tem a vantagem significativa de poder pesquisar endereços na Classe 1,2 ou 3 sub-redes usando varreduras de intervalo indexado (WHERE ip BETWEEN fnBinaryIPv4 ('132.31.55.00') AND fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung
1
@RBarryYoung Eu o armazenaria como um número inteiro. você poderia explicar qual é a vantagem de desempenho de armazená-lo como binário?
Pacerier,
3
@Pacerier: 1) veja um comentário anterior para um exemplo e 2) Eu não afirmei que o binário seria mais rápido do que o inteiro. Afirmei que A) é o formato correto (e é) e B) não seria mais lento.
RBarryYoung
1
Sim, você está incorreto, não é isso que Dan está dizendo. Além disso, este não é um fórum de discussão e não é adequado para isso. Stackoverflow é um froum de perguntas e respostas, se você tiver uma pergunta, poste.
RBarryYoung
23

Você pode usar varchar. O comprimento do IPv4 é estático, mas o do IPv6 pode ser altamente variável.

A menos que você tenha um bom motivo para armazená-lo como binário, use um tipo de string (textual).

NDC
fonte
39
O comprimento do IPv6 é muito fixo - 128 bits.
Broam
4
A menos que você esteja falando sobre dados que um ser humano nunca irá ler ou uma grande quantidade de dados, esta é a melhor resposta.
Aren Cambre
10
Uma razão simples para usar binários e não strings: a versão binária permite a verificação de intervalo numérico de endereços IP! A versão em texto não. É claro que isso depende do uso necessário, mas os números binários são mais úteis porque têm um significado real.
Gone Coding
4
varchar ocupa significativamente mais espaço no banco de dados. Um endereço IPv4 de 32 bits leva 4 bytes para armazenar numericamente e um endereço IPv6 de 128 bits leva 16 bytes para armazenar numericamente. Enquanto isso, esse endereço IPv4 leva 15 bytes para armazenar como string e um endereço IPv6 pode levar até 39 bytes como string.
Aaron Schultz
1
varbinary (16) é o caminho a percorrer
jjxtra
17

Aqui está algum código para converter IPV4 ou IPv6 no formato varchar para binário (16) e vice-versa. Esta é a menor forma que eu poderia pensar. Ele deve indexar bem e fornecer uma maneira relativamente fácil de filtrar em sub-redes. Requer SQL Server 2005 ou posterior. Não tenho certeza se é totalmente à prova de balas. Espero que isto ajude.

-- 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
fonte
Essa resposta funcionou perfeitamente para o banco de dados db-ip IP to country. Uma conversão de ida e volta mostrou apenas pequenas diferenças onde os 0s foram cortados de ipv6 (inicial e posterior).
crokusek
1
Em ToBinary (), encontre alguns problemas com o plano de consulta e o uso de fn_varbintohexstr () que não está marcado como determinístico. Que tal para o else '.' seção: select @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Parece equivalente. Não há necessidade de @zona ou mecanismo xml? Parece uma boa aceleração se o mecanismo xml foi removido de alguma forma de ':' também.
crokusek
concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) converterá um longo sem sinal contendo um endereço IP em um forma legível por humanos.
theking2
@ theking2 - isso não se aplica ao SQL Server, pois >> não é compatível
Alex
Observe que há um bug no fn_ConvertIpAddressToBinary. Veja a resposta de C.Plock e a minha .
Alex
10

Como desejo lidar com IPv4e IPv6, estou usando VARBINARY(16)as seguintes SQL CLRfunções para converter a textapresentação do endereço IP em bytes e vice-versa:

[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
fonte
8

Para pessoas que usam .NET, podem usar a classe IPAddress para analisar a string IPv4 / IPv6 e armazená-la como um VARBINARY(16). Pode usar a mesma classe para converter byte[]em string. Se quiser converter o VARBINARYem 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
fonte
7

sys.dm_exec_connectionsusa varchar (48) após o SQL Server 2005 SP1. Parece bom o suficiente para mim, especialmente se você quiser usá-lo para comparar com o seu valor.

Realisticamente, você ainda não verá o IPv6 como mainstream por um tempo, então eu prefiro a rota 4 tinyint. Dito isso, estou usando varchar (48) porque tenho que usarsys.dm_exec_connections ...

De outra forma. A resposta de Mark Redman menciona uma questão anterior do debate do SO .

gbn
fonte
4
realisticamente, veremos IPv6
Pacerier
10
Realisticamente, não veremos o ano 2000 por um tempo ainda, podemos usar datas de 2 dígitos para economizar alguns bytes. Oh espere.
Eric J.
1

Obrigado RBarry. Estou montando um sistema de alocação de bloco de IP e armazenar como binário é o único caminho a percorrer.

Estou armazenando a representação CIDR (ex: 192.168.1.0/24) do bloco IP em um campo varchar e usando 2 campos calculados para manter a forma binária do início e do final do bloco. A partir daí, posso executar consultas rápidas para ver se um determinado bloco já foi alocado ou está livre para atribuir.

Modifiquei sua função para calcular o endereço IP final da seguinte forma:

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
fonte
1

Eu geralmente uso uma filtragem VARCHAR simples e antiga para um endereço IP funciona bem.

Se você quiser filtrar por intervalos de endereço IP, dividirei em quatro números inteiros.

Daniel Elliott
fonte
1
O que é um intervalo? Nem todas as sub-redes têm 8 bytes. Qual é o intervalo de endereços IP da rede em que este host está: 50.50.50.50/20?
Bradley Kreider,
2
Os inteiros são muito grandes para armazenar um valor de 0 a 255. Em vez disso, use um tinyint.
SandRock
0

Gosto das funções do SandRock. Mas encontrei um erro no código de dbo.fn_ConvertIpAddressToBinary . O parâmetro de entrada de @ipAddress VARCHAR (39) é muito pequeno quando você concata o @delim a ele.

SET @ipAddress = @ipAddress + @delim

Você pode aumentar para 40. Ou melhor ainda, usar uma nova variável maior e usá-la internamente. Dessa forma, você não perde o último par em grandes números.

SELECT dbo.fn_ConvertIpAddressToBinary('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
C.Plock
fonte
De fato, há um bug
Alex
0

A seguinte resposta é baseada nas respostas de M. Turnhout e Jerry Birchler a esta pergunta, mas com as seguintes melhorias:

  • Substituído o uso de funções não documentadas ( sys.fn_varbintohexsubstring, fn_varbintohexstr) CONVERT()por estilos binários
  • Substituído XML "hacks" ( CAST('' as xml).value('xs:hexBinary())) CONVERT()por estilos binários
  • Corrigido bug na implementação de Jerry Birchlerfn_ConvertIpAddressToBinary (conforme apontado por C.Plock )
  • Adicionar açúcar de sintaxe menor

O código foi testado no SQL Server 2014 e SQL Server 2016 (consulte os casos de teste no final)

IPAddressVarbinaryToString

Converte valores de 4 bytes em IPV4 e valores de 16 bytes em representações de string IPV6 . Observe que esta função não encurta endereços.

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 teste:

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

Converte representações de string IPV4 e IPV6 em valores binários de 4 bytes e 16 bytes, respectivamente. Observe que esta função é capaz de analisar a maioria (todas as comumente usadas) das representações de endereço abreviado (por exemplo, 127 ... 1 e 2001: db8 :: 1319: 370: 7348). Para forçar a função fina a sempre retornar valores binários de 16 bytes, remova o comentário da concatenação de 0s inicial no final da função.

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 teste

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
fonte
-2

Estou usando varchar(15)até agora tudo está funcionando para mim. Inserir, atualizar, selecionar. Acabei de iniciar um aplicativo que tem endereços IP, embora ainda não tenha feito muito trabalho de desenvolvimento.

Aqui está a declaração de seleção:

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