Тип даних для зберігання ip адреси в SQL Server


113

Який тип даних слід вибрати для зберігання IP-адреси на SQL-сервері?

Вибравши правильний тип даних, було б досить легко фільтрувати за IP-адресою?


Подивіться на цю відповідь: stackoverflow.com/questions/1038950/…
Марк Редман

Відповіді:


130

Технічно правильний спосіб зберігання IPv4 - це двійковий (4), оскільки таким він є насправді (ні, навіть не INT32 / INT (4), числова текстова форма, яку ми всі знаємо і любимо (255.255.255.255), просто дисплейне перетворення його бінарного вмісту).

Якщо ви зробите це таким чином, ви хочете, щоб функції перетворилися у формат текстового дисплея та з нього:

Ось як перетворити текстову форму відображення у бінарну:

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

Ось як перетворити бінарне назад у форму текстового відображення:

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

Ось демонстрація способів їх використання:

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

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

Нарешті, виконуючи пошук і порівнюючи, завжди використовуйте двійкову форму, якщо ви хочете мати можливість використовувати ваші індекси.


ОНОВЛЕННЯ:

Я хотів додати, що один із способів вирішити притаманні проблеми продуктивності скалярних UDF в SQL Server, але все-таки зберегти кодове повторне використання функції - це замість цього використовувати iTVF (вбудовану функцію в таблиці). Ось як можна переписати першу функцію вище (рядок у двійковий) як 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

Ось це в прикладі:

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

А ось як би ви його використовували в ВСТУП

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

33
Я думаю, що це правильно лише в академічному сенсі. Не знаючи мети та доменної проблеми, яку плакат намагається вирішити, я підозрюю, що це зайво ускладнить взаємодію з даними та потенційно погіршить продуктивність.
Ерік Сабін

21
IPv4 - упорядкована послідовність з чотирьох байтів. Це - це домен, а у форматі зберігання - це BIN (4). Формат зберігання не буде заважати продуктивності, оскільки це оптимальний формат. Функція перетворення може (через те, що udf всмоктується на SQL-сервері), що може бути вирішено або за допомогою вбудованої лінії, або за допомогою перетворення на клієнті. Нарешті, цей підхід має істотну перевагу в тому, що він може шукати адреси в класах 1,2 або 3 підмережах, використовуючи сканування індексованого діапазону (WHERE ip BETWEEN fnBinaryIPv4 ('132.31.55.00') AND fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung

1
@RBarryYoung Я б зберігав це як ціле число. Ви могли б пояснити, яка перевага для продуктивності зберігання його як бінарного?
Pacerier

3
@Pacerier: 1) див. Приклад попереднього коментаря; 2) Я не стверджував, що Binary буде швидше, ніж Integer. Я стверджував, що A) Це правильний формат (і він є), і B) він не був би повільнішим.
RBarryYoung

1
Так, ви неправі, це не те, що говорить Дан. Також це не дискусійний форум, і він не підходить для нього. Stackoverflow - це питання з питань запитання, якщо у вас є питання, будь ласка, опублікуйте його.
RBarryYoung

23

Можна використовувати варчар. Довжина IPv4 є статичною, але довжина IPv6 може бути дуже мінливою.

Якщо у вас немає вагомих причин зберігати його як бінарне, дотримуйтесь рядкового (текстового) типу.


39
Довжина IPv6 дуже фіксована - 128 біт.
Брам

4
Якщо ви не говорите про дані, які людина ніколи не прочитає або про велику кількість даних, це найкраща відповідь.
Арен Камбре

10
Одна проста причина використовувати двійкові, а не рядки: двійкова версія дозволяє перевірити числовий діапазон IP-адрес! Текстова версія - ні. Це, звичайно, залежить від необхідного використання, але двійкові числа є більш корисними, оскільки вони мають фактичне значення.
Пройшов кодування

4
varchar займає значно більше місця в БД. 32-розрядна IPv4-адреса для чисельного зберігання займає 4 байти, а 128-розрядна IPv6-адреса зберігає 16 байт. Тим часом ця IPv4-адреса зберігає 15 байт як рядок, а IPv6-адреса може приймати до 39 байт як рядок.
Аарон Шульц

1
варбінар (16) - це шлях
jjxtra

17

Ось якийсь код для перетворення IPV4 або IPv6 у варчарському форматі у двійковий (16) та назад. Це найменша форма, яку я міг придумати. Він повинен добре індексувати і забезпечувати відносно простий спосіб фільтрації в підмережах. Потрібен SQL Server 2005 або новішої версії. Не впевнений, що це абсолютно куленепробивна. Сподіваюся, це допомагає.

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

Ця відповідь спрацювала бездоганно для бази даних db-ip IP для країни. Конверсія в зворотній бік показала лише незначні відмінності, коли 0 були відрізані від ipv6 (ведучого та наступного).
crokusek

1
У ToBinary () виберіть деякі проблеми із планом запитів та використанням fn_varbintohexstr (), який не позначений як детермінований. Як щодо іншого "." розділ: виберіть @ vbzone = перетворити (varbinary (2), convert (tinyint, @ token))? Здається еквівалентним. Не потрібна @ зона чи двигун xml? Виглядає як гарна швидкість, якщо двигун xml якось видалено з ':'.
crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) перетворить непідписаний довгий вміст адреси IP людська читана форма.
theking2

@ theking2 - це не стосується SQL Server, оскільки >> не підтримується
Alex

Зауважте, що помилка в fn_ConvertIpAddressToBinary. Дивіться відповідь C.Plock і мою .
Олексій

10

Оскільки я хочу обробляти і те, IPv4і IPv6я використовую VARBINARY(16)такі SQL CLRфункції, щоб перетворити textпрезентацію IP-адреси в байти та зворотно:

[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, можна використовувати клас IPAddress для розбору рядка IPv4 / IPv6 та збереження його як VARBINARY(16). Можна використовувати той же клас для перетворення byte[]в рядок. Якщо ви хочете перетворити VARBINARYв 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_connectionsвикористовує varchar (48) після SQL Server 2005 SP1. Звучить для мене досить добре, особливо якщо ви хочете використовувати його порівняно зі своїм значенням.

Реально ви ще не побачите IPv6 як основний потік деякий час, тому я віддаю перевагу 4 крихітному маршруту. Сказавши це, я використовую varchar (48), тому що мені потрібно користуватисяsys.dm_exec_connections ...

Інакше. У відповіді Марка Редмана згадується попередня дискусія щодо ПП запитання питання.


4
реально ми будемо бачити IPv6
Pacerier

10
Реально ми ще деякий час не побачимо 2000 рік, а також можемо використовувати двозначні дати, щоб зберегти кілька байт. Чекай.
Ерік Дж

1

Спасибі RBarry. Я збираю систему розподілу блоків IP і зберігаю як бінарний - єдиний шлях.

Я зберігаю представлення CIDR (наприклад: 192.168.1.0/24) блоку IP у варшарському полі та використовую 2 обчислені поля для утримання бінарної форми початку та кінця блоку. Звідти я можу запускати швидкі запити, щоб побачити, чи визначений блок як уже виділений, чи вільний призначати.

Я змінив вашу функцію, щоб обчислити кінцеву IP-адресу так:

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

Зазвичай я використовую звичайну стару фільтрацію VARCHAR для IPAddress.

Якщо ви хочете відфільтрувати діапазони IP-адреси, я б розбив її на чотири цілі числа.


1
Що таке діапазон? Не всі підмережі мають 8 байт. Який діапазон IP-адрес для мережі, на якій знаходиться хост: 50.50.50.50/20?
Бредлі Крейдер

2
Цілі лічильники занадто великі, щоб зберігати значення 0-255. Використовуйте замість крихітки.
SandRock

0

Мені подобаються функції SandRock. Але я виявив помилку в коді dbo.fn_ConvertIpAddressToBinary . Вхідний параметр @ipAddress VARCHAR (39) занадто малий, коли ви присвоюєте @delim до нього.

SET @ipAddress = @ipAddress + @delim

Ви можете збільшити її до 40. Або ще краще використовувати нову змінну, яка є більшою, і використовувати її всередині. Таким чином ви не втратите останню пару у великій кількості.

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

Дійсно є помилка
Алекс

0

Наступна відповідь заснована на відповідях М. Тернхаута та Джеррі Бірхлера на це запитання, але з наступними вдосконаленнями:

  • Замінено використання недокументованих функцій ( sys.fn_varbintohexsubstring, fn_varbintohexstr) на CONVERT()для двійкових стилів
  • Замінено "хакі" ( CAST('' as xml).value('xs:hexBinary())) XML на ) CONVERT()для двійкові стилі
  • Виправлена помилка в Джеррі Birchler реалізації «s з fn_ConvertIpAddressToBinary(як зазначив C.Plock )
  • Додайте незначний синтаксичний цукор

Код був протестований у SQL Server 2014 та SQL Server 2016 (див. Тестові приклади в кінці)

IPAddressVarbinaryToString

Перетворює 4 байтних значень у IPV4 та 16 байтних значень у представленнях рядків IPV6 . Зауважте, що ця функція не скорочує адреси.

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

Випробування:

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

Перетворює представлення рядків IPV4 та IPV6 у двійкові значення 4 байти та 16 байт відповідно. Зауважте, що ця функція здатна проаналізувати більшість (усіх загальновживаних) представлень скорочень адрес (наприклад, 127 ... 1 та 2001: db8 :: 1319: 370: 7348). Щоб змусити функцію тонкості завжди повертати 16-байтові бінарні значення, коментовуючи, що веде 0s конкатенацію в кінці функції.

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

Випробування

Дійсні справи

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

Недійсні справи

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) поки що все працює на мене. Вставити, оновити, вибрати. Я тільки що запустив додаток, який має адреси IP, хоча я ще не робив багато розробок.

Ось оператор select:

select * From dbo.Server 
where  [IP] = ('132.46.151.181')
Go
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.