代码之家  ›  专栏  ›  技术社区  ›  Quibblesome

从MySQL移植到T-SQL。有同等的inet_Aton()吗?

  •  5
  • Quibblesome  · 技术社区  · 15 年前

    需要将一些代码从mysql移到tsql。我有两个对inet Aton的调用,它将类似于ipaddress的字符串转换为数字。是否有T-SQL等价物?

    5 回复  |  直到 10 年前
        1
  •  12
  •   GSerg    15 年前

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

    不过,这里不支持“短格式地址”这一功能。

        2
  •  3
  •   Andomar    15 年前

    下面是一个将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')
    
        3
  •  1
  •       13 年前

    稍微好一点。它使用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;
    
        4
  •  1
  •   Paul White    12 年前

    两个小改进。

    1. 作为内联表值函数写入
    2. 围绕着这样一个事实 PARSENAME non-deterministic

    功能:

    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;
    
        5
  •  1
  •   Levite    10 年前

    与直接回答您的问题相比,这是一个更为不同的选择(我看到下降票数即将到来^),但您也可以考虑将转换逻辑放入您的软件,而不是查询中。根据语言和用例的不同,这可能会更好。

    实例

    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;
    

    你也可以给它 -1 null long? 或者编写一个方法来抛出异常,以防转换失败。

    蟒蛇

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

    在你开始投反对票之前:这只是一个简短的例子,我知道这里没有错误处理。

    结论

    当然,让DBS做这项工作大多数时候是更好的,但这确实取决于情况,如果你没有一个每秒有数百万请求的项目,这可能会有所帮助。