SQL Server에 IP 주소를 저장하기위한 데이터 유형


답변:


130

IPv4를 저장하는 기술적으로 올바른 방법은 binary (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

마지막으로, 조회 및 비교를 수행 할 때 인덱스를 활용하려면 항상 이진 형식을 사용하십시오.


최신 정보:

SQL Server에서 스칼라 UDF의 고유 한 성능 문제를 해결하기위한 한 가지 방법을 추가하고 싶었지만 함수의 코드 재사용을 유지하는 대신 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
나는 이것이 학문적 의미에서만 옳다고 생각합니다. 포스터가 해결하려는 목적과 도메인 문제를 모르면 데이터와의 상호 작용이 불필요하게 복잡해지고 잠재적으로 성능이 저하 될 것입니다.
Eric Sabine

21
IPv4는 순서가 지정된 4 바이트 시퀀스입니다. 즉, IS 그것의 도메인 및 저장 포맷에 BIN (4)의 것이다. 저장 형식은 최적의 형식이므로 성능을 방해하지 않습니다. 변환 함수는 (SQL 서버에서 udf가 짜증나 기 때문에) 인라인하거나 클라이언트에서 변환을 수행하여 해결할 수 있습니다. 마지막으로,이 방법은 인덱스 범위 스캔을 사용하여 클래스 1, 2, 3 개 서브 네트워크에 주소를 검색 할 수있는 큰 장점이있다 (WHERE IP fnBinaryIPv4 ( '132.31.55.00')와 fnBinaryIPv4 (BETWEEN '132.31.55.255'))
RBarryYoung

1
@RBarryYoung 나는 그것을 정수로 저장할 것입니다. 바이너리로 저장할 때의 성능 이점이 무엇인지 설명해 주시겠습니까?
Pacerier

3
@Pacerier : 1) 예를 들어 이전 주석을 참조하고 2) Binary가 Integer보다 빠르다고 주장하지 않았습니다. 나는 A) 올바른 형식이며 B) 느리지 않을 것이라고 주장했습니다.
RBarryYoung

1
예, 틀 렸습니다. Dan이 말한 것이 아닙니다. 또한 이것은 토론 포럼이 아니며 적합하지 않습니다. Stackoverflow는 Q & A 포럼입니다. 질문이 있으면 게시 해주세요.
RBarryYoung 2011 년

23

varchar를 사용할 수 있습니다. IPv4의 길이는 고정적이지만 IPv6의 길이는 매우 가변적 일 수 있습니다.

바이너리로 저장할 이유가없는 한 문자열 (텍스트) 유형을 사용하십시오.


39
IPv6의 길이는 128 비트로 매우 고정되어 있습니다.
Broam

4
인간이 결코 읽지 않을 데이터 나 방대한 양의 데이터에 대해 이야기하지 않는 한 이것이 최선의 답입니다.
Aren Cambre 2014 년

10
문자열이 아닌 바이너리를 사용하는 간단한 이유 : 바이너리 버전 은 IP 주소의 숫자 범위 검사를 허용 합니다! 텍스트 버전은 그렇지 않습니다. 이것은 물론 필요한 용도에 따라 다르지만 이진수는 실제 의미가 있으므로 더 유용합니다.
Gone Coding

4
varchar는 DB에서 훨씬 더 많은 공간을 차지합니다. 32 비트 IPv4 주소는 숫자로 저장하는 데 4 바이트가 걸리고 128 비트 IPv6 주소는 숫자로 저장하는 데 16 바이트가 필요합니다. 한편, IPv4 주소는 문자열로 저장하는 데 15 바이트가 걸리며 IPv6 주소는 문자열로 최대 39 바이트를 차지할 수 있습니다.
Aaron Schultz

1
(16) VARBINARY 길을 가야하는 것입니다
jjxtra

17

다음은 varchar 형식의 IPV4 또는 IPv6를 binary (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 () 사용에 문제가 발생했습니다. 다른 '.'는 어떻습니까? 섹션 : select @ vbzone = convert (varbinary (2), convert (tinyint, @ token))? 동등한 것 같습니다. @ zone 또는 xml 엔진이 필요하지 않습니까? xml 엔진이 ':'에서도 어떻게 든 제거하면 멋진 속도 향상처럼 보입니다.
crokusek

concat_ws ( '.', (IPAddr & 0xFF000000) >> 24, (IPAddr & 0xFF0000) >> 16, (IPAddr & 0xFF00) >> 8, (IPAddr & 0xFF))는 IP 주소를 포함하는 unsigned long을 a 사람이 읽을 수있는 형태.
theking2

@ theking2->>는 지원되지 않으므로 SQL Server에는 적용되지 않습니다
Alex

에 버그가 fn_ConvertIpAddressToBinary있습니다. C.Plock 의 대답과 내를 참조하십시오 .
Alex

10

IPv4및을 모두 처리하고 싶기 때문에 및 다음 함수를 IPv6사용 하여 IP 주소 표시를 바이트 및 그 반대로 변환합니다 .VARBINARY(16)SQL CLRtext

[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[]문자열 로 변환 할 수 있습니다 . VARBINARYin 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_connectionsSQL Server 2005 SP1 이후에 varchar (48)를 사용합니다. 특히 당신이 당신의 가치와 비교하여 그것을 사용하고 싶다면 나에게 충분하게 들립니다.

현실적으로, 당신은 아직 IPv6를 주류로 보지 않을 것이기 때문에 저는 4 개의 tinyint 경로를 선호합니다. 즉, 나는 사용해야하기 때문에 varchar (48)을 사용하고 있습니다.sys.dm_exec_connections ...

그렇지 않으면. Mark Redman의 답변은 이전 SO 토론 질문을 언급합니다 .


4
현실적으로 우리는 것입니다 IPv6를 볼 수있을
Pacerier

10
현실적으로 우리는 한동안 2000 년을 보지 못할 것이며 몇 바이트를 절약하기 위해 2 자리 날짜를 사용하는 것이 좋습니다. 아, 기다려.
Eric J.

1

감사합니다 RBarry. IP 블록 할당 시스템을 구성하고 바이너리로 저장하는 것이 유일한 방법입니다.

IP 블록의 CIDR 표현 (예 : 192.168.1.0/24)을 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

일반적으로 IPAddress에 대해 일반 이전 VARCHAR 필터링을 사용하면 정상적으로 작동합니다.

IP 주소 범위를 필터링하려면 4 개의 정수로 나눕니다.


1
범위는 무엇입니까? 모든 서브넷이 8 바이트는 아닙니다. 이 호스트가있는 네트워크의 IP 주소 범위는 50.50.50.50/20입니까?
Bradley Kreider 2011

2
정수가 너무 커서 0-255 값을 저장할 수 없습니다. 대신 tinyint를 사용하세요.
SandRock 2015 년

0

나는 SandRock의 기능을 좋아합니다. 하지만 dbo.fn_ConvertIpAddressToBinary 코드에서 오류를 발견했습니다 . @delim을 연결할 때 @ipAddress VARCHAR (39)의 수신 매개 변수가 너무 작습니다.

SET @ipAddress = @ipAddress + @delim

40으로 늘릴 수 있습니다. 또는 더 큰 새 변수를 사용하고 내부적으로 사용할 수 있습니다. 이렇게하면 많은 수에서 마지막 쌍을 잃지 않습니다.

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

실제로 버그가 있습니다
Alex

0

다음 답변은 이 질문 에 대한 M. TurnhoutJerry Birchler의 답변을 기반으로 하지만 다음과 같이 개선되었습니다.

  • 문서화되지 않은 함수 ( sys.fn_varbintohexsubstring, fn_varbintohexstr)의 사용 CONVERT()이진 스타일 용으로 대체했습니다.
  • XML "hacks"( CAST('' as xml).value('xs:hexBinary())) CONVERT()바이너리 스타일 용으로 대체했습니다.
  • Jerry Birchler 의 구현 버그 수정 fn_ConvertIpAddressToBinary( C.Plock이 지적한 대로 )
  • 사소한 구문 설탕 추가

코드는 SQL Server 2014SQL 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

IPV4IPV6 문자열 표현을 각각 4 바이트 및 16 바이트 2 진 값으로 변환 합니다. 이 함수는 대부분의 (일반적으로 사용되는) 단축 주소 표현 (예 : 127 ... 1 및 2001 : db8 :: 1319 : 370 : 7348)을 구문 분석 할 수 있습니다. thins 함수가 항상 16 바이트 이진 값을 반환하도록 강제하려면 함수 끝에서 선행 0 연결의 주석 처리를 제거하십시오.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.