ms SQL函数使IP地址字典序可比
Ms SQL function to make IP addresses lexicographically comparable
我发现以下代码用零填充 IP 地址,使其在字典序上具有可比性。
该代码可以正常工作,但我需要它作为 SQL 中的标量函数。
您能否在 Code 中对其进行转换以创建一个具有相同功能的标量函数?
我们目前使用 SQL Server 2008 R2。
DECLARE @a as NVARCHAR(15)
SET @a = '2.18.4.14'
SELECT
@a = CASE
WHEN CHARINDEX('.',@a) < 4
THEN STUFF(@a,1,0,REPLICATE('0',4-CHARINDEX('.',@a,1)))
ELSE @a
END
,
@a = CASE
WHEN CHARINDEX('.',@a) < 8
THEN STUFF(@a,5,0,REPLICATE('0',8-CHARINDEX('.',@a, 5)))
ELSE @a
END
,
@a = CASE
WHEN CHARINDEX('.',@a) < 12
THEN STUFF(@a,9,0,REPLICATE('0',12-CHARINDEX('.',@a, 9)))
ELSE @a
END
,
@a = CASE
WHEN LEN(@a) < 15
THEN STUFF(@a,13,0,REPLICATE('0',15-LEN(@a)))
ELSE @a
END
SELECT @a
您能解释一下该代码的工作原理吗?
我了解 CHARINDEX、STUFF 和 REPLICATE 的作用,但我不了解 CASE 步骤如何修改 IP 地址 @a 的步骤。
是标量值还是 table?
就我个人而言,我会使用 Table-值函数,而不是标量函数。 Table-Value Function 执行标量函数的速度远远超过标量函数,如果您要针对数据集执行此操作,那么您会注意到速度大幅提高。
首先,这利用了 Jeff Moden 的 DelmitedSplit8k。但是,如果您使用的是 SQL Server 2016,那么您可以使用 STRING_SPLIT
(我不知道您使用的是什么版本)。那么函数就这么简单:
CREATE FUNCTION Lexicon_IP_fn (@IPAddress VARCHAR(15))
RETURNS TABLE AS
RETURN
(
SELECT CONVERT(varchar(15),STUFF((SELECT '.' + RIGHT('000' + DS.Item,3)
FROM DelimitedSplit8K(@IPAddress, '.') DS
FOR XML PATH('')),1,1,'')) AS Lexicon_IP
);
您可以使用 CROSS APPLY
调用函数。例如:
WITH VTE AS (
SELECT *
FROM (VALUES ('1.1.1.1'),('123.123.1.42'),('127.0.0.1')) V([IP]))
SELECT [IP], LIP.Lexicon_IP
FROM VTE
CROSS APPLY Lexicon_IP_fn([IP]) LIP;
哪个returns:
IP Lexicon_IP
------------ ---------------
1.1.1.1 001.001.001.001
123.123.1.42 123.123.001.042
127.0.0.1 127.000.000.001
我发现以下代码用零填充 IP 地址,使其在字典序上具有可比性。 该代码可以正常工作,但我需要它作为 SQL 中的标量函数。 您能否在 Code 中对其进行转换以创建一个具有相同功能的标量函数? 我们目前使用 SQL Server 2008 R2。
DECLARE @a as NVARCHAR(15)
SET @a = '2.18.4.14'
SELECT
@a = CASE
WHEN CHARINDEX('.',@a) < 4
THEN STUFF(@a,1,0,REPLICATE('0',4-CHARINDEX('.',@a,1)))
ELSE @a
END
,
@a = CASE
WHEN CHARINDEX('.',@a) < 8
THEN STUFF(@a,5,0,REPLICATE('0',8-CHARINDEX('.',@a, 5)))
ELSE @a
END
,
@a = CASE
WHEN CHARINDEX('.',@a) < 12
THEN STUFF(@a,9,0,REPLICATE('0',12-CHARINDEX('.',@a, 9)))
ELSE @a
END
,
@a = CASE
WHEN LEN(@a) < 15
THEN STUFF(@a,13,0,REPLICATE('0',15-LEN(@a)))
ELSE @a
END
SELECT @a
您能解释一下该代码的工作原理吗? 我了解 CHARINDEX、STUFF 和 REPLICATE 的作用,但我不了解 CASE 步骤如何修改 IP 地址 @a 的步骤。 是标量值还是 table?
就我个人而言,我会使用 Table-值函数,而不是标量函数。 Table-Value Function 执行标量函数的速度远远超过标量函数,如果您要针对数据集执行此操作,那么您会注意到速度大幅提高。
首先,这利用了 Jeff Moden 的 DelmitedSplit8k。但是,如果您使用的是 SQL Server 2016,那么您可以使用 STRING_SPLIT
(我不知道您使用的是什么版本)。那么函数就这么简单:
CREATE FUNCTION Lexicon_IP_fn (@IPAddress VARCHAR(15))
RETURNS TABLE AS
RETURN
(
SELECT CONVERT(varchar(15),STUFF((SELECT '.' + RIGHT('000' + DS.Item,3)
FROM DelimitedSplit8K(@IPAddress, '.') DS
FOR XML PATH('')),1,1,'')) AS Lexicon_IP
);
您可以使用 CROSS APPLY
调用函数。例如:
WITH VTE AS (
SELECT *
FROM (VALUES ('1.1.1.1'),('123.123.1.42'),('127.0.0.1')) V([IP]))
SELECT [IP], LIP.Lexicon_IP
FROM VTE
CROSS APPLY Lexicon_IP_fn([IP]) LIP;
哪个returns:
IP Lexicon_IP
------------ ---------------
1.1.1.1 001.001.001.001
123.123.1.42 123.123.001.042
127.0.0.1 127.000.000.001