Type de données pour stocker l'adresse IP dans SQL Server

Réponses:

130

Le moyen techniquement correct de stocker IPv4 est binaire (4), puisque c'est ce qu'il est réellement (non, même pas un INT32 / INT (4), la forme textuelle numérique que nous connaissons et aimons tous (255.255.255.255) étant juste la conversion d'affichage de son contenu binaire).

Si vous procédez de cette façon, vous souhaiterez que les fonctions soient converties vers et à partir du format d'affichage textuel:

Voici comment convertir le formulaire d'affichage textuel en binaire:

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

Et voici comment reconvertir le binaire au format d'affichage textuel:

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

Voici une démonstration de leur utilisation:

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

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

Enfin, lorsque vous effectuez des recherches et des comparaisons, utilisez toujours la forme binaire si vous souhaitez pouvoir exploiter vos index.


METTRE À JOUR:

Je voulais ajouter qu'une façon de résoudre les problèmes de performances inhérents aux UDF scalaires dans SQL Server, tout en conservant la réutilisation du code d'une fonction, consiste à utiliser à la place un iTVF (fonction table en ligne). Voici comment la première fonction ci-dessus (chaîne en binaire) peut être réécrite en 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

Voici dans l'exemple:

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

Et voici comment vous l'utiliseriez dans un INSERT

INSERT INTo myIpTable
SELECT {other_column_values,...},
       (SELECT bin FROM dbo.itvfBinaryIPv4('192.65.68.201'))
RBarryYoung
la source
33
Je pense que ce n'est correct que dans un sens académique. Sans connaître le problème de but et de domaine pour lequel l'affiche tente de résoudre, je soupçonne que cela compliquera inutilement l'interaction avec les données et dégradera potentiellement les performances.
Eric Sabine
21
IPv4 est une séquence ordonnée de quatre octets. C'EST domaine de, et au format de stockage qui est un BIN (4). Le format de stockage n'interférera pas avec les performances car c'est le format optimal. La fonction de conversion pourrait (car udf est nul sur le serveur SQL), ce qui peut être résolu soit en alignant ou en effectuant la conversion sur le client. Enfin, cette approche a l'avantage significatif de pouvoir rechercher des adresses dans des sous-réseaux de classe 1, 2 ou 3 à l'aide de balayages de plage indexés (WHERE ip BETWEEN fnBinaryIPv4 ('132.31.55.00') AND fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung
1
@RBarryYoung Je le stockerais sous forme d'entier. pourriez-vous expliquer quel est l'avantage en termes de performances de le stocker sous forme de fichier binaire?
Pacerier
3
@Pacerier: 1) voir le commentaire précédent pour un exemple, et 2) je n'ai pas prétendu que Binary serait plus rapide que Integer. J'ai affirmé que A) c'est le bon format (et c'est le cas), et B) ce ne serait pas plus lent.
RBarryYoung
1
Oui, vous avez tort, ce n'est pas ce que dit Dan. De plus, ce n'est pas un forum de discussion et il ne lui convient pas. Stackoverflow est un forum de questions / réponses, si vous avez une question, veuillez la poster.
RBarryYoung
23

Vous pouvez utiliser varchar. La longueur d'IPv4 est statique, mais celle d'IPv6 peut être très variable.

Sauf si vous avez une bonne raison de le stocker en tant que binaire, tenez-vous-en à un type de chaîne (textuel).

NDC
la source
39
La longueur d'IPv6 est très fixe - 128 bits.
Broam du
4
À moins que vous ne parliez de données qu'un humain ne lira jamais ou d'une quantité massive de données, c'est la meilleure réponse.
Aren Cambre
10
Une raison simple d'utiliser du binaire et non des chaînes: la version binaire permet la vérification numérique des plages d'adresses IP! La version texte ne le fait pas. Cela dépend bien sûr de l'utilisation requise, mais les nombres binaires sont plus utiles car ils ont une signification réelle.
Fini le codage du
4
varchar occupe beaucoup plus d'espace dans la base de données. Une adresse IPv4 32 bits prend 4 octets pour stocker numériquement, et une adresse IPv6 128 bits prend 16 octets pour stocker numériquement. Pendant ce temps, cette adresse IPv4 prend 15 octets pour être stockée sous forme de chaîne et une adresse IPv6 peut prendre jusqu'à 39 octets sous forme de chaîne.
Aaron Schultz
1
varbinary (16) est la voie à suivre
jjxtra
17

Voici un code pour convertir IPV4 ou IPv6 au format varchar en binaire (16) et inversement. C'est la plus petite forme à laquelle je puisse penser. Il devrait bien indexer et fournir un moyen relativement simple de filtrer sur les sous-réseaux. Nécessite SQL Server 2005 ou version ultérieure. Pas sûr que ce soit totalement à l'épreuve des balles. J'espère que cela t'aides.

-- 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
la source
Cette réponse a parfaitement fonctionné pour la base de données db-ip IP to country. Une conversion aller-retour n'a montré que des différences mineures où les 0 ont été supprimés de l'ipv6 (avant et après).
crokusek
1
Dans ToBinary (), rencontrez des problèmes avec le plan de requête et l'utilisation de fn_varbintohexstr () qui n'est pas marqué comme déterministe. Que diriez-vous de l'autre ». section: sélectionnez @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Cela semble équivalent. Pas besoin de @ zone ou de moteur xml? Cela ressemble à une belle accélération si le moteur xml est également supprimé de ':'.
crokusek
concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) convertira un long non signé contenant une adresse IP en un forme lisible par l'homme.
theking2 le
@ theking2 - cela ne s'applique pas à SQL Server car >> n'est pas pris en charge
Alex
Notez qu'il y a un bogue dans fn_ConvertIpAddressToBinary. Voir la réponse de C.Plock et la mienne .
Alex le
10

Comme je veux gérer à la fois IPv4et IPv6, j'utilise VARBINARY(16)et les SQL CLRfonctions suivantes pour convertir la textprésentation de l'adresse IP en octets et inversement:

[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
la source
8

Les personnes utilisant .NET peuvent utiliser la classe IPAddress pour analyser la chaîne IPv4 / IPv6 et la stocker en tant que fichier VARBINARY(16). Peut utiliser la même classe pour convertir byte[]en chaîne. Si vous voulez convertir le 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
la source
7

sys.dm_exec_connectionsutilise varchar (48) après SQL Server 2005 SP1. Cela me semble assez bien, surtout si vous voulez l'utiliser par rapport à votre valeur.

En réalité, vous ne verrez pas encore IPv6 comme un courant dominant, alors je préférerais la route 4 tinyint. En disant cela, j'utilise varchar (48) car je dois utilisersys.dm_exec_connections ...

Autrement. La réponse de Mark Redman mentionne une précédente question de débat sur l' OS .

gbn
la source
4
de manière réaliste, nous verrons IPv6
Pacerier
10
En réalité, nous ne verrons pas encore l'an 2000 avant un certain temps, nous pouvons aussi utiliser des dates à 2 chiffres pour économiser quelques octets. Oh, attendez.
Eric J.
1

Merci RBarry. Je mets en place un système d'allocation de bloc IP et le stockage en tant que binaire est la seule voie à suivre.

Je stocke la représentation CIDR (ex: 192.168.1.0/24) du bloc IP dans un champ varchar et j'utilise 2 champs calculés pour contenir la forme binaire du début et de la fin du bloc. À partir de là, je peux exécuter des requêtes rapides pour voir si un bloc donné a déjà été alloué ou s'il est libre de l'attribuer.

J'ai modifié votre fonction pour calculer l'adresse IP de fin comme ceci:

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
la source
1

J'utilise généralement un ancien filtrage VARCHAR pour une adresse IP fonctionne très bien.

Si vous voulez filtrer sur des plages d'adresses IP, je le diviserais en quatre entiers.

Daniel Elliott
la source
1
Qu'est-ce qu'une gamme? Tous les sous-réseaux ne font pas 8 octets. Quelle est la plage d'adresses IP du réseau sur lequel cet hôte se trouve: 50.50.50.50/20?
Bradley Kreider
2
Les entiers sont trop gros pour stocker une valeur comprise entre 0 et 255. Utilisez plutôt un tinyint.
SandRock
0

J'aime les fonctions de SandRock. Mais j'ai trouvé une erreur dans le code de dbo.fn_ConvertIpAddressToBinary . Le paramètre entrant de @ipAddress VARCHAR (39) est trop petit lorsque vous y concattez @delim.

SET @ipAddress = @ipAddress + @delim

Vous pouvez l'augmenter à 40. Ou mieux encore, utilisez une nouvelle variable plus grande et utilisez-la en interne. De cette façon, vous ne perdez pas la dernière paire sur de grands nombres.

SELECT dbo.fn_ConvertIpAddressToBinary('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
C.Plock
la source
En effet, il y a un bug
Alex le
0

La réponse suivante est basée sur les réponses de M. Turnhout et Jerry Birchler à cette question, mais avec les améliorations suivantes:

  • Remplacement de l'utilisation de fonctions non documentées ( sys.fn_varbintohexsubstring, fn_varbintohexstr) par CONVERT()des styles binaires
  • Remplacement des "hacks" XML ( CAST('' as xml).value('xs:hexBinary())) par CONVERT()des styles binaires
  • Correction d'un bug dans l' implémentation de Jerry Birchler de fn_ConvertIpAddressToBinary(comme indiqué par C.Plock )
  • Ajouter du sucre de syntaxe mineur

Le code a été testé dans SQL Server 2014 et SQL Server 2016 (voir les cas de test à la fin)

IPAddressVarbinaryToString

Convertit les valeurs de 4 octets en IPV4 et les valeurs de 16 octets en représentations de chaîne IPV6 . Notez que cette fonction ne raccourcit pas les adresses.

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

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

Convertit les représentations de chaîne IPV4 et IPV6 en valeurs binaires de 4 octets et 16 octets respectivement. Notez que cette fonction est capable d'analyser la plupart des représentations d'adresses abrégées (par exemple, 127 ... 1 et 2001: db8 :: 1319: 370: 7348) (toutes celles couramment utilisées). Pour forcer la fonction thins à toujours renvoyer des valeurs binaires de 16 octets, décommentez la concaténation de 0 à la fin de la fonction.

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

Cas de test

Cas valides

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

Cas invalides

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
la source
-2

J'utilise varchar(15)jusqu'ici tout fonctionne pour moi. Insérer, mettre à jour, sélectionner. Je viens de démarrer une application avec des adresses IP, même si je n'ai pas encore fait beaucoup de travail de développement.

Voici l'instruction select:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Profond
la source