Datatype untuk menyimpan alamat ip di SQL Server


Jawaban:


130

Cara yang benar secara teknis untuk menyimpan IPv4 adalah biner (4), karena memang demikian adanya (tidak, bahkan bukan INT32 / INT (4), bentuk tekstual numerik yang kita semua kenal dan sukai (255.255.255.255) adalah adil konversi tampilan konten binernya).

Jika Anda melakukannya dengan cara ini, Anda akan menginginkan fungsi untuk dikonversi ke dan dari format tampilan tekstual:

Berikut cara mengubah bentuk tampilan tekstual menjadi biner:

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

Dan inilah cara mengubah biner kembali ke bentuk tampilan tekstual:

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

Berikut demo cara menggunakannya:

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

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

Terakhir, saat melakukan pencarian dan perbandingan, selalu gunakan bentuk biner jika Anda ingin dapat memanfaatkan indeks Anda.


MEMPERBARUI:

Saya ingin menambahkan bahwa salah satu cara untuk mengatasi masalah kinerja bawaan dari UDF skalar di SQL Server, tetapi masih mempertahankan penggunaan kembali kode dari suatu fungsi adalah dengan menggunakan iTVF (fungsi bernilai tabel sebaris) sebagai gantinya. Berikut ini bagaimana fungsi pertama di atas (string ke biner) dapat ditulis ulang sebagai 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

Ini dia dalam contoh:

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

Dan inilah cara Anda menggunakannya dalam INSERT

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

33
Saya pikir ini hanya benar dalam arti akademis. Tanpa mengetahui tujuan dan masalah domain yang coba dipecahkan oleh poster, saya curiga hal ini akan mempersulit interaksi dengan data dan berpotensi menurunkan kinerja.
Eric Sabine

21
IPv4 adalah urutan empat byte. Itu IS domainnya, dan dalam format penyimpanan itu BIN (4). Format penyimpanan tidak akan mengganggu kinerja karena ini adalah format yang optimal. Fungsi konversi mungkin (karena udf payah di SQL server), yang dapat diselesaikan baik dengan in-lineing atau melakukan konversi pada klien. Terakhir, pendekatan ini memiliki keuntungan signifikan karena dapat mencari alamat di subnetwork Kelas 1,2, atau 3 menggunakan pemindaian rentang terindeks (WHERE ip BETWEEN fnBinaryIPv4 ('132.31.55.00') AND fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung

1
@RBarryYoung Saya akan menyimpannya sebagai integer. dapatkah Anda menjelaskan apa keunggulan performa dari menyimpannya sebagai biner?
Pacerier

3
@Pacerier: 1) lihat komentar sebelumnya sebagai contoh, dan 2) Saya tidak mengklaim bahwa Binary akan lebih cepat dari Integer. Saya menyatakan bahwa A) Ini adalah format yang benar (dan memang demikian), dan B) tidak akan lebih lambat.
RBarryYoung

1
Ya, Anda tidak benar, bukan itu yang dikatakan Dan. Selain itu, ini bukan forum diskusi, dan tidak cocok untuk itu. Stackoverflow adalah sesi Tanya Jawab, jika Anda memiliki pertanyaan, silakan kirimkan.
RBarryYoung

23

Anda dapat menggunakan varchar. Panjang IPv4 statis, tetapi IPv6 mungkin sangat bervariasi.

Kecuali jika Anda memiliki alasan kuat untuk menyimpannya sebagai biner, tetap gunakan tipe string (tekstual).


39
Panjang IPv6 sangat tetap - 128 bit.
Broam

4
Kecuali jika Anda berbicara tentang data yang tidak akan pernah dibaca manusia atau data dalam jumlah besar, ini adalah jawaban terbaik.
Aren Cambre

10
Satu alasan sederhana untuk menggunakan biner dan bukan string: Versi biner memungkinkan pemeriksaan rentang numerik alamat IP! Versi teks tidak. Ini tentu saja tergantung pada penggunaan yang diperlukan, tetapi bilangan biner lebih berguna karena memiliki arti sebenarnya.
Pergi Coding

4
varchar membutuhkan lebih banyak ruang di DB. Alamat IPv4 32-bit membutuhkan 4 byte untuk disimpan secara numerik, dan alamat IPv6 128-bit membutuhkan 16 byte untuk disimpan secara numerik. Sementara itu, alamat IPv4 itu membutuhkan 15 byte untuk disimpan sebagai string dan alamat IPv6 bisa memakan waktu hingga 39 byte sebagai string.
Aaron Schultz

1
varbinary (16) adalah cara untuk pergi
jjxtra

17

Berikut adalah beberapa kode untuk mengonversi IPV4 atau IPv6 dalam format varchar ke biner (16) dan sebaliknya. Ini adalah bentuk terkecil yang dapat saya pikirkan. Ini harus mengindeks dengan baik dan menyediakan cara yang relatif mudah untuk memfilter subnet. Membutuhkan SQL Server 2005 atau yang lebih baru. Tidak yakin itu benar-benar antipeluru. Semoga ini membantu.

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

Jawaban ini bekerja dengan sempurna untuk database db-ip IP to country. Konversi bolak-balik hanya menunjukkan perbedaan kecil di mana angka 0 dipangkas dari ipv6 (memimpin dan mengikuti).
crokusek

1
Dalam ToBinary (), mengalami beberapa masalah dengan rencana kueri dan penggunaan fn_varbintohexstr () yang tidak ditandai sebagai deterministik. Bagaimana dengan yang lain '.' bagian: pilih @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Sepertinya setara. Tidak perlu mesin @ zone atau xml? Sepertinya speedup bagus jika mesin xml dihapus entah bagaimana dari ':' juga.
crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) akan mengubah unsigned long berisi alamat IP menjadi bentuk yang dapat dibaca manusia.
theking2

@ theking2 - ini tidak berlaku untuk SQL Server karena >> tidak didukung
Alex

Perhatikan bahwa ada bug di fn_ConvertIpAddressToBinary. Lihat jawaban C. Lock dan jawaban saya .
Alex

10

Karena saya ingin menangani keduanya IPv4dan IPv6, saya menggunakan VARBINARY(16)dan SQL CLRfungsi berikut untuk mengubah textpresentasi alamat IP menjadi byte dan sebaliknya:

[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

Bagi orang yang menggunakan .NET dapat menggunakan kelas IPAddress untuk mengurai string IPv4 / IPv6 dan menyimpannya sebagai file VARBINARY(16). Dapat menggunakan kelas yang sama untuk dikonversi byte[]menjadi string. Jika ingin mengonversi VARBINARYdalam 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_connectionsmenggunakan varchar (48) setelah SQL Server 2005 SP1. Kedengarannya cukup bagus untuk saya terutama jika Anda ingin menggunakannya dibandingkan dengan nilai Anda.

Secara realistis, Anda tidak akan melihat IPv6 sebagai arus utama untuk sementara waktu, jadi saya lebih suka rute 4 tinyint. Mengatakan itu, saya menggunakan varchar (48) karena saya harus menggunakansys.dm_exec_connections ...

Jika tidak. Jawaban Mark Redman menyebutkan pertanyaan debat SO sebelumnya .


4
secara realistis kita akan melihat IPv6
Pacerier

10
Secara realistis kita tidak akan melihat Tahun 2000 untuk sementara waktu, mungkin juga menggunakan tanggal 2 digit untuk menghemat beberapa byte. Oh tunggu.
Eric J.

1

Terima kasih RBarry. Saya menyusun sistem alokasi blok IP dan menyimpan sebagai biner adalah satu-satunya cara untuk melakukannya.

Saya menyimpan representasi CIDR (mis .: 192.168.1.0/24) dari blok IP di bidang varchar, dan menggunakan 2 bidang terhitung untuk menampung bentuk biner dari awal dan akhir blok. Dari sana, saya dapat menjalankan kueri cepat untuk melihat apakah blok yang diberikan telah dialokasikan atau bebas untuk ditetapkan.

Saya memodifikasi fungsi Anda untuk menghitung Alamat IP akhir seperti:

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

Saya biasanya menggunakan penyaringan VARCHAR lama biasa untuk IPAddress berfungsi dengan baik.

Jika Anda ingin memfilter rentang alamat IP, saya akan membaginya menjadi empat bilangan bulat.


1
Berapakah kisaran? Tidak semua subnet berukuran 8 byte. Berapakah kisaran alamat IP untuk jaringan yang digunakan host ini: 50.50.50.50/20?
Bradley Kreider

2
Bilangan bulat terlalu besar untuk menyimpan nilai 0-255. Gunakan tinyint sebagai gantinya.
SandRock

0

Saya suka fungsi SandRock. Tetapi saya menemukan kesalahan pada kode dbo.fn_ConvertIpAddressToBinary . Parameter masuk dari @ipAddress VARCHAR (39) terlalu kecil saat Anda menggabungkan @delim ke dalamnya.

SET @ipAddress = @ipAddress + @delim

Anda bisa meningkatkannya menjadi 40. Atau lebih baik lagi gunakan variabel baru yang lebih besar dan gunakan itu secara internal. Dengan begitu Anda tidak kehilangan pasangan terakhir dalam jumlah besar.

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

Memang ada bug
Alex

0

Jawaban berikut ini berdasarkan jawaban M. Turnhout dan Jerry Birchler atas pertanyaan ini tetapi dengan perbaikan berikut:

  • Mengganti penggunaan fungsi tak berdokumen ( sys.fn_varbintohexsubstring, fn_varbintohexstr) denganCONVERT() untuk gaya biner
  • Mengganti XML "hacks" ( CAST('' as xml).value('xs:hexBinary())) denganCONVERT() untuk gaya biner
  • Fixed bug di Jerry Birchler pelaksanaan 's dari fn_ConvertIpAddressToBinary(sebagai keluar menunjuk oleh C.Plock )
  • Tambahkan gula sintaks minor

Kode telah diuji di SQL Server 2014 dan SQL Server 2016 (lihat kasus uji di bagian akhir)

IPAddressVarbinaryToString

Mengonversi nilai 4 byte menjadi IPV4 dan nilai 16 byte menjadi representasi string IPV6 . Perhatikan bahwa fungsi ini tidak mempersingkat alamat.

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

Kasus Uji:

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

Mengonversi representasi string IPV4 dan IPV6 menjadi nilai biner 4 byte dan 16 byte. Perhatikan bahwa fungsi ini dapat mengurai sebagian besar (semua yang umum digunakan) dari representasi alamat singkatan (misalnya 127 ... 1 dan 2001: db8 :: 1319: 370: 7348). Untuk memaksa fungsi menipiskan agar selalu mengembalikan nilai biner 16 byte, hapus komentar yang memimpin penggabungan 0 di akhir fungsi.

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

Kasus Uji

Kasus yang valid

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

Kasus tidak valid

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

Saya menggunakan varchar(15)sejauh ini semuanya bekerja untuk saya. Sisipkan, Perbarui, Pilih. Saya baru saja memulai aplikasi yang memiliki Alamat IP, meskipun saya belum melakukan banyak pekerjaan pengembang.

Berikut adalah pernyataan pilih:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.