Tipo di dati per la memorizzazione dell'indirizzo IP in SQL Server


Risposte:


130

Il modo tecnicamente corretto per memorizzare IPv4 è binario (4), poiché è quello che è in realtà (no, nemmeno un INT32 / INT (4), la forma numerica testuale che tutti conosciamo e amiamo (255.255.255.255) è solo la conversione del display del suo contenuto binario).

Se lo fai in questo modo, vorrai che le funzioni da convertire nel e dal formato di visualizzazione testuale:

Ecco come convertire il modulo di visualizzazione testuale in 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

Ed ecco come riconvertire il file binario nel modulo di visualizzazione testuale:

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

Ecco una demo di come usarli:

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

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

Infine, quando esegui ricerche e confronti, usa sempre il modulo binario se vuoi essere in grado di sfruttare i tuoi indici.


AGGIORNARE:

Volevo aggiungere che un modo per affrontare i problemi di prestazioni intrinseci delle UDF scalari in SQL Server, ma mantenere comunque il riutilizzo del codice di una funzione è utilizzare invece un iTVF (funzione in linea con valori di tabella). Ecco come la prima funzione sopra (da stringa a binario) può essere riscritta come 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

Eccolo nell'esempio:

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

Ed ecco come lo useresti in un INSERT

INSERT INTo myIpTable
SELECT {other_column_values,...},
       (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))

33
Penso che questo sia corretto solo in senso accademico. Senza conoscere lo scopo e il problema del dominio per il quale il poster sta cercando di risolvere, sospetto che ciò complicherà inutilmente l'interazione con i dati e potenzialmente ridurrà le prestazioni.
Eric Sabine,

21
IPv4 è una sequenza ordinata di quattro byte. Che IS è di dominio, e in formato di archiviazione che è un BIN (4). Il formato di archiviazione non interferirà con le prestazioni perché è il formato ottimale. La funzione di conversione potrebbe (perché udf fa schifo sul server SQL), che può essere risolta sia in linea che eseguendo la conversione sul client. Infine, questo approccio ha il vantaggio significativo di poter cercare indirizzi in sottoreti di Classe 1,2 o 3 utilizzando scansioni a intervalli indicizzati (WHERE ip BETWEEN fnBinaryIPv4 ('132.31.55.00') AND fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung

1
@RBarryYoung lo memorizzerei come numero intero. potresti spiegare qual è il vantaggio in termini di prestazioni di memorizzarlo come binario?
Pacerier

3
@Pacerier: 1) vedere il commento precedente per un esempio e 2) non ho affermato che Binary sarebbe più veloce di Integer. Ho affermato che A) è il formato corretto (e lo è) e B) non sarebbe più lento.
RBarryYoung

1
Sì, ti sbagli, non è quello che dice Dan. Inoltre, questo non è un forum di discussione e non è adatto per questo. Stackoverflow è un froum di domande e risposte, se hai una domanda, per favore pubblicala.
RBarryYoung

23

Puoi usare varchar. La lunghezza di IPv4 è statica, ma quella di IPv6 può essere molto variabile.

A meno che tu non abbia una buona ragione per memorizzarlo come binario, usa un tipo stringa (testuale).


39
La lunghezza di IPv6 è molto fissa: 128 bit.
Broam

4
A meno che non si parli di dati che un essere umano non leggerà mai o di una quantità enorme di dati, questa è la risposta migliore.
Aren Cambre

10
Un semplice motivo per utilizzare binari e non stringhe: la versione binaria consente il controllo dell'intervallo numerico degli indirizzi IP! La versione testuale no. Questo ovviamente dipende dall'uso richiesto, ma i numeri binari sono più utili in quanto hanno un significato reale.
Gone Coding

4
varchar occupa molto più spazio nel database. Un indirizzo IPv4 a 32 bit richiede 4 byte per la memorizzazione numerica e un indirizzo IPv6 a 128 bit richiede 16 byte per la memorizzazione numerica. Nel frattempo, quell'indirizzo IPv4 richiede 15 byte per essere archiviato come stringa e un indirizzo IPv6 può richiedere fino a 39 byte come stringa.
Aaron Schultz,

1
varbinary (16) è la strada da percorrere
jjxtra

17

Ecco del codice per convertire IPV4 o IPv6 in formato varchar in binario (16) e viceversa. Questa è la forma più piccola a cui potrei pensare. Dovrebbe indicizzare bene e fornire un modo relativamente semplice per filtrare le sottoreti. Richiede SQL Server 2005 o successivo. Non sono sicuro che sia totalmente a prova di proiettile. Spero che questo ti aiuti.

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

Questa risposta ha funzionato perfettamente per l'IP db-ip al database del paese. Una conversione di andata e ritorno ha mostrato solo piccole differenze in cui gli 0 sono stati tagliati da ipv6 (iniziale e successivo).
crokusek

1
In ToBinary (), riscontri alcuni problemi con il piano di query e l'uso di fn_varbintohexstr () che non è contrassegnato come deterministico. E per il resto "." sezione: seleziona @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Sembra equivalente. Non c'è bisogno di @ zone o motore xml? Sembra un buon aumento della velocità se il motore xml viene rimosso in qualche modo anche da ":".
crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) convertirà un long senza segno contenente un indirizzo IP in un forma leggibile dall'uomo.
theking2

@ theking2 - questo non si applica a SQL Server in quanto >> non è supportato
Alex

Nota che c'è un bug in fn_ConvertIpAddressToBinary. Vedi la risposta di C.Plock e la mia .
Alex

10

Poiché voglio gestire sia IPv4e IPv6, sto usando VARBINARY(16)e le seguenti SQL CLRfunzioni per convertire la textpresentazione dell'indirizzo IP in byte e viceversa:

[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);
}

8

Gli utenti che utilizzano .NET possono utilizzare la classe IPAddress per analizzare la stringa IPv4 / IPv6 e memorizzarla come file VARBINARY(16). Può usare la stessa classe per convertire byte[]in stringa. Se vuoi convertire il VARBINARYin 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

7

sys.dm_exec_connectionsutilizza varchar (48) dopo SQL Server 2005 SP1. Suona abbastanza bene per me, soprattutto se vuoi usarlo rispetto al tuo valore.

Realisticamente, non vedrai IPv6 come mainstream ancora per un po ', quindi preferirei il percorso 4 tinyint. Detto questo, sto usando varchar (48) perché devo usare sys.dm_exec_connections...

Altrimenti. La risposta di Mark Redman menziona una precedente domanda del dibattito SO .


4
realisticamente ci sarà assisteremo IPv6
Pacerier

10
Realisticamente non vedremo l'anno 2000 ancora per un po ', potremmo anche usare date a 2 cifre per salvare alcuni byte. Oh, aspetta.
Eric J.

1

Grazie RBarry. Sto mettendo insieme un sistema di allocazione di blocchi IP e archiviare come binario è l'unico modo per andare.

Sto memorizzando la rappresentazione CIDR (es: 192.168.1.0/24) del blocco IP in un campo varchar e utilizzando 2 campi calcolati per contenere la forma binaria dell'inizio e della fine del blocco. Da lì, posso eseguire query veloci per vedere se un determinato blocco è già stato allocato o è libero di assegnarlo.

Ho modificato la tua funzione per calcolare l'indirizzo IP finale in questo modo:

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

1

Di solito uso un semplice vecchio filtro VARCHAR per un indirizzo IP che funziona bene.

Se vuoi filtrare su intervalli di indirizzi IP, lo spezzerei in quattro numeri interi.


1
Cos'è una gamma? Non tutte le sottoreti sono 8 byte. Qual è l'intervallo di indirizzi IP per la rete su cui si trova questo host: 50.50.50.50/20?
Bradley Kreider

2
I numeri interi sono troppo grandi per memorizzare un valore compreso tra 0 e 255. Usa invece un tinyint.
SandRock

0

Mi piacciono le funzioni di SandRock. Ma ho trovato un errore nel codice di dbo.fn_ConvertIpAddressToBinary . Il parametro in entrata di @ipAddress VARCHAR (39) è troppo piccolo quando si concatena il @delim ad esso.

SET @ipAddress = @ipAddress + @delim

Puoi aumentarlo a 40. O meglio ancora, usa una nuova variabile più grande e usala internamente. In questo modo non perdi l'ultima coppia su grandi numeri.

SELECT dbo.fn_ConvertIpAddressToBinary('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')

In effetti c'è un bug
Alex

0

La seguente risposta si basa sulle risposte di M. Turnhout e Jerry Birchler a questa domanda, ma con i seguenti miglioramenti:

  • Sostituito l'uso di funzioni non documentate ( sys.fn_varbintohexsubstring, fn_varbintohexstr) con CONVERT()per gli stili binari
  • Sostituito XML "hack" ( CAST('' as xml).value('xs:hexBinary())) con CONVERT()per gli stili binari
  • Risolto bug nell'implementazione di Jerry Birchler di fn_ConvertIpAddressToBinary(come sottolineato da C.Plock )
  • Aggiungi zucchero di sintassi minore

Il codice è stato testato in SQL Server 2014 e SQL Server 2016 (vedere casi di test alla fine)

IPAddressVarbinaryToString

Converte i valori di 4 byte in IPV4 e i valori di 16 byte in rappresentazioni di stringa IPV6 . Notare che questa funzione non abbrevia gli indirizzi.

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

Casi test:

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 le rappresentazioni di stringa IPV4 e IPV6 rispettivamente in valori binari a 4 byte e 16 byte. Si noti che questa funzione è in grado di analizzare la maggior parte (tutte quelle comunemente usate) delle rappresentazioni di indirizzi abbreviati (ad esempio 127 ... 1 e 2001: db8 :: 1319: 370: 7348). Per forzare la funzione thins a restituire sempre valori binari a 16 byte, rimuovere il commento dalla concatenazione di 0 alla fine della funzione.

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

Casi test

Casi validi

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

Casi non validi

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

-2

Sto usando varchar(15)finora tutto funziona per me. Inserisci, Aggiorna, Seleziona. Ho appena avviato un'app con indirizzi IP, anche se non ho ancora svolto molto lavoro di sviluppo.

Ecco la dichiarazione select:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.