从MySql移植到T-Sql。任何INET_ATON()等效?

时间:2009-03-29 23:01:41

标签: sql mysql tsql

需要将一些代码从MySql移动到TSql。我有一些对INET_ATON的调用,它将类似于IPAddress的字符串转换为数字。是否有T-SQL等价物?

5 个答案:

答案 0 :(得分:12)

滥用parsname函数:

create function INET_ATON (@addr varchar(15))
returns bigint
with schemabinding
as
begin
  return  
    cast(parsename(@addr, 4) as bigint) * 16777216 +
    cast(parsename(@addr, 3) as bigint) * 65536 +
    cast(parsename(@addr, 2) as bigint) * 256 +
    cast(parsename(@addr, 1) as bigint)
end

虽然这里不支持“简短地址”的事情。

答案 1 :(得分:3)

这是将IP地址转换为字符串的功能:

CREATE FUNCTION dbo.IpToString 
    (@ip_str VarChar(15))
returns BigInt
as
    begin
    declare @i int
    declare @dot_pos int
    declare @current_part VarChar(15)
    declare @result BigInt

    set @result = 0
    set @i = 0

    while Len(@ip_str) > 0
        begin
        set @i = @i + 1
        set @dot_pos = CharIndex('.', @ip_str)
        if @dot_pos > 0
            begin
            set @current_part = Left(@ip_str, @dot_pos - 1)
            set @ip_str = SubString(@ip_str, @dot_pos + 1, 15)
            end
        else 
            begin
            set @current_part = @ip_str
            set @ip_str = ''
            end

        if Len(@current_part) > 3 Return(Null)
        if IsNumeric(@current_part) = 0 Return (Null)
        if not cast(@current_part as int) between 0 and 255 Return (Null)
        set @result = 256 * @result + Cast(@current_part as BigInt)
        end

    if @i = 4 Return(@result)

    Return(Null)
    end

创建函数后,您可以将其命名为:

select dbo.IpToString('1.2.3.4')

答案 2 :(得分:1)

好一点。它使用int(4b)而不是bigint(8b)。你的结果应该只有四个字节......每个八位字节一个:

create function INET_ATON (@ip varchar(15))
returns int
begin
    declare @rslt int 
    -- This first part is a little error checking
    -- Looks for three dots and all numbers when not dots 
    if len(@ip) - len(replace(@ip,'.','')) = 3 
        AND
            isnumeric(replace(@ip,'.','')) = 1
    begin 
    set @rslt = convert(int,
            convert(binary(1),convert(tinyint,parsename(@ip, 4)))
        +   convert(binary(1),convert(tinyint,parsename(@ip, 3)))
        +   convert(binary(1),convert(tinyint,parsename(@ip, 2)))
        +   convert(binary(1),convert(tinyint,parsename(@ip, 1)))
        )
    end
    else set @rslt = 0
    return @rslt
end;

答案 3 :(得分:1)

两项小改进。

  1. 作为内联表值函数编写
  2. 解决PARSENAMEnon-deterministic
  3. 这一事实

    功能:

    CREATE FUNCTION dbo.IPv4ToInt 
    (
        @ip varchar(15)
    )
    RETURNS TABLE
    WITH SCHEMABINDING
    AS
    RETURN
        SELECT
            IPv4Int =
            CASE
                WHEN LEN(@ip) - LEN(REPLACE(@ip COLLATE Latin1_General_BIN2, '.', '')) = 3
                AND @ip COLLATE Latin1_General_BIN2 NOT LIKE '%[^.0-9]%'
                AND @ip COLLATE Latin1_General_BIN2 LIKE '[0-9]%.[0-9]%.[0-9]%.[0-9]%'
                    THEN
                    CONVERT
                    (
                        integer,
                        (
                            CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) - 1)))
                            +
                            CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) - 1)))
                            +
                            CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1)) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) - 1)))
                            +
                            CONVERT(binary(1), CONVERT(tinyint, SUBSTRING(@ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1)) + 1, LEN(@ip) - (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, (CHARINDEX('.', @ip COLLATE Latin1_General_BIN2, 1)) + 1)) + 1)))))
                        )
                    )
                ELSE NULL
            END;
    

    显示函数的属性:

    SELECT
        IsDeterministic = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsDeterministic'),
        IsSystemVerified = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsSystemVerified'),
        IsPrecise = OBJECTPROPERTYEX(OBJECT_ID(N'dbo.IPv4ToInt', N'IF'), 'IsPrecise');
    

    用法示例:

    DECLARE @Data TABLE
    (
        IPv4    varchar(15) NULL
    );
    
    INSERT @Data
        (IPv4)
    VALUES
        ('192.168.0.3'),
        ('0.0.0.0'),
        ('10.0.16.129'),
        ('255.255.255.255');
    
    SELECT * 
    FROM @Data AS d      
    CROSS APPLY dbo.IPv4ToInt(d.IPv4) AS ipti;
    

答案 4 :(得分:1)

更多不同的选项,而不是直接回答你的问题(我看到即将到来的^),但你也可以考虑将转换逻辑放入你的软件而不是查询中。根据语言和用例,这可能会更好。

实施例

PHP ip2long("192.168.1.1");

C / C ++ inet_addr("192.168.1.1");

C#

System.Net.IPAddress ip;
long ipn = (System.Net.IPAddress.TryParse("192.168.1.1", out ip))

    ? (((long) ip.GetAddressBytes()[0] << 24) | (ip.GetAddressBytes()[1] << 16) |
              (ip.GetAddressBytes()[2] <<  8) |  ip.GetAddressBytes()[3])

    : 0;

你也可以给它-1null(以long?作为数据类型),或者编写一个抛出异常的方法,以防转换失败。

Python

reduce(lambda sum, chunk: sum <<8 | chunk, map(int, '192.168.1.1'.split(".")))

开始downvoting之前:这只是一个简短的例子,我知道这里没有错误处理。

结论

当然,大多数时候让dbs完成这项工作更好,但这实际上取决于,如果你没有一个每秒有数百万个请求的项目,这可能会有所帮助。