IP adresini SQL Server'da depolamak için veri türü


Yanıtlar:


130

IPv4'ü depolamanın teknik olarak doğru yolu ikilidir (4), çünkü gerçekte olan budur (hayır, bir INT32 / INT (4) bile değil, hepimizin bildiği ve sevdiği sayısal metin biçimi (255.255.255.255) sadece ikili içeriğinin ekran dönüşümü).

Bunu bu şekilde yaparsanız, işlevlerin metinsel görüntüleme biçimine ve metin biçiminden dönüştürülmesini isteyeceksiniz:

Metinsel görüntüleme formunu ikiliye nasıl dönüştüreceğiniz aşağıda açıklanmıştır:

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

Ve işte ikiliyi metinsel gösterim biçimine nasıl geri dönüştüreceğiniz:

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

İşte bunların nasıl kullanılacağına dair bir demo:

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

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

Son olarak, arama ve karşılaştırmalar yaparken, dizinlerinizden yararlanabilmek istiyorsanız her zaman ikili formu kullanın.


GÜNCELLEME:

SQL Server'daki skaler UDF'lerin doğasında olan performans sorunlarını çözmenin bir yolunu eklemek istedim, ancak yine de bir işlevin yeniden kod kullanımını sürdürmek yerine bir iTVF (satır içi tablo değerli işlev) kullanmaktır. Yukarıdaki ilk işlev (dizeden ikiliye) bir iTVF olarak nasıl yeniden yazılabilir:

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

İşte örnekte:

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

Ve işte onu bir INSERT'te nasıl kullanacağınız

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

33
Bunun sadece akademik anlamda doğru olduğunu düşünüyorum. Posterin çözmeye çalıştığı amacı ve etki alanı sorununu bilmeden, bunun verilerle etkileşimi gereksiz yere karmaşıklaştıracağından ve performansı potansiyel olarak düşüreceğinden şüpheleniyorum.
Eric Sabine

21
IPv4, dört baytlık sıralı bir dizidir. Bu , etki alanı ve depolama biçiminde bir BIN (4). Depolama biçimi, en uygun biçim olduğu için performansı etkilemeyecektir. Dönüştürme işlevi (çünkü udf SQL sunucusunda emilir), bu da satır içi olarak veya istemcide dönüştürme yaparak çözülebilir. Son olarak, bu yaklaşım, dizinlenmiş aralık taramalarını kullanarak Sınıf 1,2 veya 3 alt ağdaki adresleri arayabilmesi açısından önemli bir avantaja sahiptir (FnBinaryIPv4 ('132.31.55.00') VE fnBinaryIPv4 ('132.31.55.255') ARASINDA ip NEREDE)
RBarryYoung

1
@RBarryYoung Ben tamsayı olarak saklardım. onu ikili olarak depolamanın performans avantajı nedir açıklayabilir misiniz?
Pacerier

3
@Pacerier: 1) bir örnek için önceki yoruma bakın ve 2) Binary'nin Tamsayı'dan daha hızlı olacağını iddia etmedim. A) Doğru format olduğunu (ve öyle) ve B) daha yavaş olmayacağını iddia ettim.
RBarryYoung

1
Evet, yanılıyorsun, Dan'in söylediği bu değil. Ayrıca, bu bir tartışma forumu değildir ve buna uygun değildir. Stackoverflow bir Soru-Cevap grubudur, eğer bir sorunuz varsa lütfen gönderin.
RBarryYoung

23

Varchar kullanabilirsiniz. IPv4'ün uzunluğu statiktir, ancak IPv6'nın uzunluğu oldukça değişken olabilir.

İkili olarak saklamak için iyi bir nedeniniz olmadıkça, bir dize (metinsel) türüne bağlı kalın.


39
IPv6'nın uzunluğu çok sabittir - 128 bit.
Broam

4
Bir insanın asla okumayacağı verilerden veya büyük miktarda veriden bahsetmiyorsanız, bu en iyi cevaptır.
Aren Cambre

10
Dizeleri değil, ikili kullanmak için basit bir neden: İkili sürüm , IP adreslerinin sayısal aralık kontrolüne izin verir ! Metin versiyonu yok. Bu elbette gerekli kullanıma bağlıdır, ancak ikili sayılar gerçek anlamlara sahip oldukları için daha kullanışlıdır.
Kodlama Gone

4
varchar, DB'de önemli ölçüde daha fazla yer kaplar. 32 bitlik bir IPv4 adresinin sayısal olarak depolanması 4 bayt, 128 bitlik bir IPv6 adresinin sayısal olarak depolanması 16 bayt alır. Bu arada, bu IPv4 adresinin bir dizge olarak depolanması 15 bayt alır ve bir IPv6 adresi, dizge olarak 39 bayta kadar sürebilir.
Aaron Schultz

1
varbinary (16) gitmenin yoludur
jjxtra

17

Varchar formatında IPV4 veya IPv6'yı ikiliye (16) ve geri dönüştürmek için bazı kodlar. Bu aklıma gelen en küçük form. İyi bir dizin oluşturmalı ve alt ağları filtrelemek için nispeten kolay bir yol sağlamalıdır. SQL Server 2005 veya sonrasını gerektirir. Tamamen kurşun geçirmez olduğundan emin değilim. Bu yardımcı olur umarım.

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

Bu cevap, ülke veritabanına db-ip IP'si için kusursuz bir şekilde çalıştı. Bir gidiş-dönüş dönüşümü, 0'ların ipv6'dan kırpıldığı yerlerde (önde ve arkada) yalnızca küçük farklılıklar gösterdi.
crokusek

1
ToBinary () 'de, sorgu planı ve deterministik olarak işaretlenmemiş fn_varbintohexstr () kullanımıyla ilgili bazı problemleri çöz. Diğerine ne dersin? ' bölüm: @ vbzone seçin = convert (varbinary (2), convert (tinyint, @ token))? Eşdeğer görünüyor. @ Zone veya xml motoruna gerek yok mu? Xml motoru ':' den bir şekilde kaldırıldıysa güzel bir hızlanma gibi görünüyor.
crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) bir IP adresi içeren bir işaretsiz long'u bir insan tarafından okunabilir form.
theking2

@ theking2 - Bu, >> desteklenmediği için SQL Server için geçerli değildir
Alex

İçinde bir hata olduğunu unutmayın fn_ConvertIpAddressToBinary. Bkz C.Plock 'ın cevabı ve maden .
Alex

10

Her iki işlemek istediğimizden IPv4ve IPv6ben kullanıyorum, VARBINARY(16)ve aşağıdaki SQL CLRişlevleri dönüştürmek için textbayt IP adresi sunum ve ters:

[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

.NET kullanan kişiler, IPv4 / IPv6 dizesini ayrıştırmak ve bunu bir VARBINARY(16). Dizeye dönüştürmek byte[]için aynı sınıfı kullanabilir . VARBINARYSQL'e dönüştürmek istiyorsanız :

--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_connectionsSQL Server 2005 SP1'den sonra varchar (48) kullanır. Benim için yeterince iyi geliyor, özellikle de kendi değerinizle karşılaştırmak istiyorsanız.

Gerçekçi olarak, IPv6'yı henüz bir süre ana akım olarak görmeyeceksiniz, bu yüzden 4 tinyint yolunu tercih ederim. Bunu söylüyorum, varchar (48) kullanıyorum çünkü kullanmak zorundayım sys.dm_exec_connections...

Aksi takdirde. Mark Redman'ın cevabı önceki bir SO tartışma sorusundan bahsediyor .


4
gerçekçi olursak olacaktır IPv6 görmeye
Pacerier

10
Gerçekçi bir şekilde 2000 Yılını henüz bir süre göremeyeceğiz, birkaç bayt tasarruf etmek için 2 basamaklı tarihler de kullanabiliriz. Bekle.
Eric J.

1

Teşekkürler RBarry. Bir IP blok tahsis sistemi kuruyorum ve gidilecek tek yol ikili olarak depolamak.

IP bloğunun CIDR temsilini (örn: 192.168.1.0/24) bir varchar alanında depoluyorum ve bloğun başlangıç ​​ve bitişinin ikili biçimini tutmak için 2 hesaplanmış alan kullanıyorum. Oradan, belirli bir bloğun önceden tahsis edilmiş veya atanmasının ücretsiz olup olmadığını görmek için hızlı sorgular çalıştırabilirim.

Bitiş IP Adresini şu şekilde hesaplamak için işlevinizi değiştirdim:

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

Bir IPAdresi için genellikle düz eski bir VARCHAR filtrelemesi kullanıyorum.

IP adresi aralıklarını filtrelemek isterseniz, onu dört tamsayıya bölerim.


1
Aralık nedir? Tüm alt ağlar 8 bayt değildir. Bu ana bilgisayarın bulunduğu ağ için IP adreslerinin aralığı nedir: 50.50.50.50/20?
Bradley Kreider

2
Tamsayılar 0-255 değerini saklayamayacak kadar büyük. Bunun yerine küçük bir değer kullanın.
Sandrock

0

SandRock'un işlevlerini seviyorum. Ancak dbo.fn_ConvertIpAddressToBinary kodunda bir hata buldum . @İpAddress VARCHAR (39) 'ın gelen parametresi, @delim'i buna bağladığınızda çok küçük.

SET @ipAddress = @ipAddress + @delim

40'a yükseltebilirsiniz. Ya da daha iyisi, daha büyük olan ve bunu dahili olarak kullanan yeni bir değişken kullanın. Bu şekilde büyük sayılarda son çifti kaybetmezsiniz.

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

Gerçekten de bir hata var
Alex

0

Aşağıdaki yanıt, M. Turnhout ve Jerry Birchler'in bu soruya verdikleri yanıtlara dayanmaktadır, ancak aşağıdaki iyileştirmelerle birlikte:

  • Belgesiz fonksiyonları (kullanımı değiştirildi sys.fn_varbintohexsubstring, fn_varbintohexstrile birlikte) CONVERT()için ikili stilleri
  • İkili stiller için XML "hack'leri" ( CAST('' as xml).value('xs:hexBinary())) ile değiştirildiCONVERT()
  • Jerry Birchler'in uygulamasındaki hata düzeltildi fn_ConvertIpAddressToBinary( C.Plock tarafından belirtildiği gibi )
  • Küçük sözdizimi şekeri ekleyin

Kod, SQL Server 2014 ve SQL Server 2016'da test edilmiştir (sondaki test durumlarına bakın)

IPAddressVarbinaryToString

4 baytlık değerleri IPV4'e ve 16 baytlık değerleri IPV6 dizgi temsillerine dönüştürür. Bu işlevin adresleri kısaltmadığını unutmayın.

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

Test Durumları:

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

Dönüştürür IPV4 ve IPV6 4 byte dize gösterimleri ve 16 sırasıyla ikili değerleri bayt. Bu işlevin, kısayol adres temsillerinin çoğunu (yaygın olarak kullanılanların tümü) ayrıştırabildiğini unutmayın (ör. 127 ... 1 ve 2001: db8 :: 1319: 370: 7348). Thins işlevini her zaman 16 baytlık ikili değerler döndürmeye zorlamak için, işlevin sonunda 0'ların birleştirmesini önleyen açıklamayı kaldırın.

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

Test Durumları

Geçerli durumlar

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

Geçersiz vakalar

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

varchar(15)Şimdiye kadar her şey benim için çalışıyor kullanıyorum . Ekle, Güncelle, Seç. Henüz çok fazla geliştirme yapmadım, ancak IP Adreslerine sahip bir uygulamayı yeni başlattım.

İşte select ifadesi:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.