【发布时间】:2010-10-16 06:50:05
【问题描述】:
需要将一些代码从 MySql 移动到 TSql。我有几个对 INET_ATON 的调用,它将一个类似于 IPAddress 的字符串转换为一个数字。是否有等效的 T-SQL?
【问题讨论】:
需要将一些代码从 MySql 移动到 TSql。我有几个对 INET_ATON 的调用,它将一个类似于 IPAddress 的字符串转换为一个数字。是否有等效的 T-SQL?
【问题讨论】:
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
这里不支持“短格式地址”。
【讨论】:
这是一个将 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')
【讨论】:
稍微好一点。它使用 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;
【讨论】:
与直接回答您的问题相比,这是一个不同的选择(我看到了反对票 ^^),但您也可以考虑将转换逻辑放入您的软件而不是查询中。根据语言和用例,这可能会更好。
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?作为数据类型),或者写一个抛出异常的方法,以防转换失败。
Python
reduce(lambda sum, chunk: sum <<8 | chunk, map(int, '192.168.1.1'.split(".")))
在你开始投票之前:这只是一个简短的例子,我知道这里没有错误处理。
当然,大多数时候让 dbs 完成这项工作会更好,但这确实取决于,如果您没有每秒处理数百万个请求的项目,这可能会有所帮助。
【讨论】: