Тип данных для хранения IP-адреса в SQL Server


113

Какой тип данных выбрать для хранения IP-адреса в SQL Server?

Будет ли тогда достаточно легко выполнить фильтрацию по 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

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

33
Думаю, это правильно только в академическом смысле. Не зная цели и предметной проблемы, которую пытается решить плакат, я подозреваю, что это излишне усложнит взаимодействие с данными и потенциально снизит производительность.
Эрик Сабин,

21
IPv4 - это упорядоченная последовательность из четырех байтов. Это IS это домен, а также в формате хранения данных, это BIN (4). Формат хранения не повлияет на производительность, потому что это оптимальный формат. Функция преобразования может (потому что udf отстой на SQL-сервере), что может быть решено либо встроенным, либо выполнением преобразования на клиенте. Наконец, этот подход имеет существенное преимущество, заключающееся в том, что он может искать адреса в подсетях класса 1,2 или 3 с использованием сканирования индексированного диапазона (ГДЕ ip BETWEEN fnBinaryIPv4 ('132.31.55.00') И fnBinaryIPv4 ('132.31.55.255'))
RBarryYoung 06

1
@RBarryYoung Я бы сохранил его как целое число. не могли бы вы объяснить, в чем преимущество хранения в двоичном формате?
Пейсер

3
@Pacerier: 1) см. Предыдущий комментарий для примера, и 2) я не утверждал, что двоичный будет быстрее, чем целое число. Я утверждал, что A) это правильный формат (и он есть), и B) он не будет медленнее.
RBarryYoung

1
Да, вы ошибаетесь, Дэн говорит не об этом. Кроме того, это не дискуссионный форум, и он для него не подходит. Stackoverflow - это форум вопросов и ответов, если у вас есть вопрос, отправьте его.
RBarryYoung

23

Вы можете использовать varchar. Длина IPv4 статична, но длина IPv6 может сильно варьироваться.

Если у вас нет веских причин хранить его как двоичный, придерживайтесь строкового (текстового) типа.


39
Длина IPv6 очень фиксированная - 128 бит.
Broam

4
Если вы не говорите о данных, которые человек никогда не прочитает, или о большом количестве данных, это лучший ответ.
Aren Cambre

10
Одна простая причина использовать двоичные, а не строки: двоичная версия позволяет проверять числовой диапазон IP-адресов! В текстовой версии нет. Это, конечно, зависит от требуемого использования, но двоичные числа более полезны, поскольку имеют реальное значение.
Gone Coding

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

1
varbinary (16)
лучший вариант

17

Вот код для преобразования IPV4 или IPv6 в формате varchar в двоичный (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 

Этот ответ работал безупречно для IP-адреса db-ip в базе данных страны. Преобразование в оба конца показало лишь незначительные отличия в тех случаях, когда нули были вырезаны из ipv6 (ведущие и последующие).
crokusek

1
В ToBinary () устраните некоторые проблемы с планом запроса и использованием fn_varbintohexstr (), который не помечен как детерминированный. А как насчет остального ». раздел: выберите @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? Кажется эквивалентным. Нет необходимости в @ zone или xml engine? Похоже, хорошее ускорение, если xml-движок каким-то образом также удален из ':'.
crokusek

concat_ws ('.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF)) преобразует длинное число без знака, содержащее IP-адрес, в человекочитаемая форма.
theking2

@ theking2 - это не относится к SQL Server, поскольку >> не поддерживается
Alex

Обратите внимание, что в fn_ConvertIpAddressToBinary. См. Ответ К.Плока и мой .
Алекс

10

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

[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 tinyint. Сказав это, я использую varchar (48), потому что мне нужно использоватьsys.dm_exec_connections ...

В противном случае. В ответе Марка Редмана упоминается предыдущий вопрос обсуждения SO .


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

10
На самом деле мы еще некоторое время не увидим 2000 год, с тем же успехом можно использовать 2-значные даты, чтобы сэкономить несколько байтов. Ой, подожди.
Эрик Дж

1

Спасибо, RBarry. Я собираю систему распределения IP-блоков и сохраняю их в двоичном формате - это единственный выход.

Я сохраняю представление CIDR (например: 192.168.1.0/24) блока IP в поле varchar и использую 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. Вместо этого используйте tinyint.
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()на бинарные стили
  • Заменены XML "hacks" ( CAST('' as xml).value('xs:hexBinary())) 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). Чтобы заставить функцию thins всегда возвращать 16-байтовые двоичные значения, раскомментируйте конкатенацию ведущих нулей в конце функции.

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.