需要将一些代码从MySql移动到TSql。我有一些对INET_ATON的调用,它将类似于IPAddress的字符串转换为数字。是否有T-SQL等价物?
答案 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)
两项小改进。
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;
答案 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;
你也可以给它-1
或null
(以long?
作为数据类型),或者编写一个抛出异常的方法,以防转换失败。
Python
reduce(lambda sum, chunk: sum <<8 | chunk, map(int, '192.168.1.1'.split(".")))
开始downvoting之前:这只是一个简短的例子,我知道这里没有错误处理。
当然,大多数时候让dbs完成这项工作更好,但这实际上取决于,如果你没有一个每秒有数百万个请求的项目,这可能会有所帮助。