Datentyp zum Speichern der IP-Adresse in SQL Server


Antworten:


130

Die technisch korrekte Art, IPv4 zu speichern, ist binär (4), da dies tatsächlich der Fall ist (nein, nicht einmal ein INT32 / INT (4), da die numerische Textform, die wir alle kennen und lieben (255.255.255.255), gerecht ist die Anzeigekonvertierung seines binären Inhalts).

Wenn Sie dies auf diese Weise tun, möchten Sie, dass Funktionen in und aus dem Textanzeigeformat konvertiert werden:

So konvertieren Sie das Textanzeigeformular in eine Binärdatei:

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

Und so konvertieren Sie die Binärdatei zurück in die Textanzeigeform:

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

Hier ist eine Demo, wie man sie benutzt:

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

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

Verwenden Sie beim Nachschlagen und Vergleichen immer die Binärform, wenn Sie Ihre Indizes nutzen möchten.


AKTUALISIEREN:

Ich wollte hinzufügen, dass eine Möglichkeit, die inhärenten Leistungsprobleme von skalaren UDFs in SQL Server zu beheben, aber die Code-Wiederverwendung einer Funktion beibehalten soll, darin besteht, stattdessen eine iTVF (Inline-Funktion mit Tabellenwert) zu verwenden. So kann die erste Funktion oben (String zu Binär) als iTVF neu geschrieben werden:

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

Hier ist es im Beispiel:

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

Und so würden Sie es in einem INSERT verwenden

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

33
Ich denke, das ist nur im akademischen Sinne richtig. Ohne den Zweck und das Domänenproblem zu kennen, für das das Poster zu lösen versucht, vermute ich, dass dies die Interaktion mit den Daten unnötig erschwert und möglicherweise die Leistung beeinträchtigt.
Eric Sabine

21
IPv4 ist eine geordnete Folge von vier Bytes. Das IST es die Domäne und in Speicherformat , das ist eine IST (4). Das Speicherformat beeinträchtigt die Leistung nicht, da es das optimale Format ist. Die Konvertierungsfunktion kann (weil udf auf SQL Server saugt), die entweder durch Inlineing oder durch die Konvertierung auf dem Client gelöst werden kann. Schließlich hat dieser Ansatz den bedeutenden Vorteil , dass es für Adressen in der Klasse 1,2 oder 3 Subnetze indizierten Bereich Scans (WHERE ip ZWISCHEN fnBinaryIPv4 ( ‚132.31.55.00‘) und fnBinaryIPv4 ( ‚132.31.55.255‘)) suchen
RBarryYoung

1
@RBarryYoung Ich würde es als Ganzzahl speichern. Können Sie erklären, was der Leistungsvorteil ist, wenn Sie es als Binärdatei speichern?
Pacerier

3
@ Pacerier: 1) Ein Beispiel finden Sie im vorherigen Kommentar, und 2) Ich habe nicht behauptet, dass Binary schneller als Integer ist. Ich habe behauptet, dass A) es das richtige Format ist (und es ist) und B) es nicht langsamer wäre.
RBarryYoung

1
Ja, du liegst falsch, das sagt Dan nicht. Auch dies ist kein Diskussionsforum und es ist nicht dafür geeignet. Stackoverflow ist ein Q & A-Froum. Wenn Sie eine Frage haben, posten Sie diese bitte.
RBarryYoung

23

Sie können varchar verwenden. Die Länge von IPv4 ist statisch, die von IPv6 kann jedoch sehr unterschiedlich sein.

Wenn Sie keinen guten Grund haben, es als Binärdatei zu speichern, bleiben Sie bei einem Zeichenfolgentyp (Text).


39
Die Länge von IPv6 ist sehr fest - 128 Bit.
Broam

4
Dies ist die beste Antwort, es sei denn, Sie sprechen von Daten, die ein Mensch niemals lesen wird, oder von einer großen Datenmenge.
Aren Cambre

10
Ein einfacher Grund, Binärdateien und keine Zeichenfolgen zu verwenden: Die Binärversion ermöglicht die Überprüfung des numerischen Bereichs von IP-Adressen! Die Textversion nicht. Dies hängt natürlich von der erforderlichen Verwendung ab, aber die Binärzahlen sind nützlicher, da sie eine tatsächliche Bedeutung haben.
Gone Coding

4
varchar nimmt in der DB deutlich mehr Platz ein. Eine 32-Bit-IPv4-Adresse benötigt 4 Byte zum numerischen Speichern, und eine 128-Bit-IPv6-Adresse benötigt 16 Byte zum numerischen Speichern. In der Zwischenzeit benötigt diese IPv4-Adresse 15 Byte, um als Zeichenfolge gespeichert zu werden, und eine IPv6-Adresse kann bis zu 39 Byte als Zeichenfolge benötigen.
Aaron Schultz

1
varbinary (16) ist der
richtige

17

Hier ist ein Code zum Konvertieren von IPV4 oder IPv6 im Varchar-Format in Binär (16) und zurück. Dies ist die kleinste Form, die ich mir vorstellen kann. Es sollte gut indizieren und eine relativ einfache Möglichkeit zum Filtern nach Subnetzen bieten. Benötigt SQL Server 2005 oder höher. Ich bin mir nicht sicher, ob es absolut kugelsicher ist. Hoffe das hilft.

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

Diese Antwort funktionierte einwandfrei für die Datenbank db-ip IP to country. Eine Roundtrip-Konvertierung zeigte nur geringfügige Unterschiede, bei denen die Nullen von ipv6 (führend und nachfolgend) abgeschnitten wurden.
Crokusek

1
Treten Sie in ToBinary () auf einige Probleme mit dem Abfrageplan und der Verwendung von fn_varbintohexstr () auf, die nicht als deterministisch markiert sind. Wie wäre es mit dem anderen '.' Abschnitt: Wählen Sie @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Scheint gleichwertig. Keine Notwendigkeit für @ Zone oder XML-Engine? Sieht nach einer guten Beschleunigung aus, wenn die XML-Engine auch irgendwie aus ':' entfernt wurde.
Crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) konvertiert ein vorzeichenloses Long mit einer IP-Adresse in a menschlich lesbare Form.
theking2

@ theking2 - Dies gilt nicht für SQL Server, da >> nicht unterstützt wird
Alex

Beachten Sie, dass ein Fehler vorliegt fn_ConvertIpAddressToBinary. Siehe die Antwort von C.Plock und meine .
Alex

10

Da ich beide IPv4und behandeln möchte IPv6, verwende ich VARBINARY(16)die folgenden SQL CLRFunktionen, um die textIP-Adressdarstellung in Bytes und umgekehrt umzuwandeln :

[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

Benutzer von .NET können die IPAddress-Klasse verwenden, um IPv4 / IPv6-Zeichenfolgen zu analysieren und als zu speichern VARBINARY(16). Kann dieselbe Klasse zum Konvertieren byte[]in einen String verwenden. Wenn Sie das VARBINARYin SQL konvertieren möchten :

--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_connectionsverwendet varchar (48) nach SQL Server 2005 SP1. Klingt gut genug für mich, besonders wenn Sie es im Vergleich zu Ihrem Wert verwenden möchten.

Realistisch gesehen werden Sie IPv6 noch eine Weile nicht als Mainstream sehen, daher würde ich die 4 tinyint-Route bevorzugen. Wenn ich das sage, benutze ich varchar (48), weil ich sys.dm_exec_connections...

Andernfalls. Mark Redmans Antwort erwähnt eine frühere SO- Debattenfrage .


4
realistisch wir werden IPv6 sehen werden
Pacerier

10
Realistisch gesehen werden wir das Jahr 2000 noch eine Weile nicht sehen, können aber auch zweistellige Daten verwenden, um ein paar Bytes zu sparen. Oh, Moment mal.
Eric J.

1

Danke RBarry. Ich stelle ein IP-Blockzuweisungssystem zusammen und das Speichern als Binärdatei ist der einzige Weg.

Ich speichere die CIDR-Darstellung (Beispiel: 192.168.1.0/24) des IP-Blocks in einem Varchar-Feld und verwende 2 berechnete Felder, um die Binärform von Anfang und Ende des Blocks zu speichern. Von dort aus kann ich schnelle Abfragen ausführen, um festzustellen, ob ein bestimmter Block bereits zugewiesen wurde oder frei zugewiesen werden kann.

Ich habe Ihre Funktion geändert, um die End-IP-Adresse wie folgt zu berechnen:

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

Normalerweise verwende ich eine einfache alte VARCHAR-Filterung für eine IPAddress.

Wenn Sie nach IP-Adressbereichen filtern möchten, würde ich diese in vier Ganzzahlen aufteilen.


1
Was ist ein Bereich? Nicht alle Subnetze sind 8 Bytes. In welchem ​​IP-Adressbereich befindet sich das Netzwerk, in dem sich dieser Host befindet: 50.50.50.50/20?
Bradley Kreider

2
Ganzzahlen sind zu groß, um einen Wert von 0-255 zu speichern. Verwenden Sie stattdessen einen winzigen Stift.
SandRock

0

Ich mag die Funktionen von SandRock. Aber ich habe einen Fehler im Code von dbo.fn_ConvertIpAddressToBinary gefunden . Der eingehende Parameter von @ipAddress VARCHAR (39) ist zu klein, wenn Sie das @delim darauf konzentrieren.

SET @ipAddress = @ipAddress + @delim

Sie können es auf 40 erhöhen. Oder besser noch eine neue Variable verwenden, die größer ist, und diese intern verwenden. Auf diese Weise verlieren Sie nicht das letzte Paar bei großen Zahlen.

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

In der Tat gibt es einen Fehler
Alex

0

Die folgende Antwort basiert auf Antworten von M. Turnhout und Jerry Birchler auf diese Frage, jedoch mit den folgenden Verbesserungen:

  • Die Verwendung von undokumentierten Funktionen ( sys.fn_varbintohexsubstring, fn_varbintohexstr) wurde durch CONVERT()for ersetzt binäre Stile ersetzt
  • XML "hacks" ( CAST('' as xml).value('xs:hexBinary())) wurde durch CONVERT()for ersetzt Binärstile
  • Fehler in Jerry Birchlers Implementierung fn_ConvertIpAddressToBinaryvon behoben (wie von C.Plock hervorgehoben )
  • Fügen Sie kleinen Syntaxzucker hinzu

Der Code wurde in SQL Server 2014 und SQL Server 2016 getestet (siehe Testfälle am Ende).

IPAddressVarbinaryToString

Konvertiert 4-Byte-Werte in IPV4- und 16-Byte-Werte in IPV6- Zeichenfolgendarstellungen. Beachten Sie, dass diese Funktion Adressen nicht verkürzt.

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

Testfälle:

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

Konvertiert IPV4- und IPV6- Zeichenfolgendarstellungen in 4-Byte- bzw. 16-Byte-Binärwerte. Beachten Sie, dass diese Funktion die meisten (alle häufig verwendeten) Kurzadressdarstellungen analysieren kann (z. B. 127 ... 1 und 2001: db8 :: 1319: 370: 7348). Um die Thins-Funktion zu zwingen, immer 16-Byte-Binärwerte zurückzugeben, kommentieren Sie die Verkettung der führenden Nullen am Ende der Funktion aus.

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

Testfälle

Gültige Fälle

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

Ungültige Fälle

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

Ich benutze varchar(15) bisher alles funktioniert für mich. Einfügen, Aktualisieren, Auswählen. Ich habe gerade eine App mit IP-Adressen gestartet, obwohl ich noch nicht viel Entwicklungsarbeit geleistet habe.

Hier ist die select-Anweisung:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.