从SQL Server 2012中的字符串返回最长的数字序列

时间:2018-08-15 16:53:33

标签: sql-server

我需要一个函数来返回字符串中最长的数字序列,例如:

P0123 / 99282返回99282,

P9-123BB-12339返回12339,

12345/54321返回12345(如果长度相同,则应返回第一个实例)。

我已经开发了这个,但是这很慢,我想知道是否有比这更快的东西:

DECLARE @str NVARCHAR(40) = N'P0120993/123-AB1239'
DECLARE @x XML
;WITH e1(n) AS(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN (SELECT 1 as t UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS b),
n(Number) AS(SELECT n = ROW_NUMBER() OVER (ORDER BY n) FROM e2)
SELECT @x = CAST(N'<A>'+ REPLACE((SELECT CAST(CAST((
        SELECT 
            CASE WHEN SUBSTRING(@str, Number, 1) like N'[^0-9]' THEN N' ' ELSE SUBSTRING(@str, Number, 1) end
        FROM n
        WHERE Number <= LEN(@str) FOR XML Path(''))
    AS xml) AS nvarchar(max))),N' ',N'</A><A>')+ N'</A>' AS XML)          
SELECT TOP 1 
    case when t.value('.', 'nvarchar(max)') = N'' then null else t.value('.', 'nvarchar(max)') end AS inVal
FROM 
    @x.nodes('/A') AS x(t)
ORDER BY
LEN(t.value('.', 'nvarchar(max)')) DESC;

说明: 我将通过的字符串的最大长度为40,我要做的是生成一个从一到四十的数字序列,从字符串中提取第N个字符,其中N是序列值,但是如果该字符不是数字,则我用空格替换,然后将XML返回为字符串,并以<A>XXX</A>

然后转换为xml,然后进行查询并以长度dec的形式返回第一项订单。

谢谢

1 个答案:

答案 0 :(得分:1)

虽然我不确定100%的性能会提高多少,但这是将字符串分解为任何可能的数字组合并返回长度最长的第一个组合的方法:

DECLARE @foo TABLE(ID varchar(40));

INSERT @foo VALUES('P0123/99282'),('P9-123BB-12339'),('12345/54321');

;WITH NumbersTable AS 
(
    SELECT TOP (40) n = ROW_NUMBER() OVER (ORDER BY Number)
    FROM master.dbo.spt_values 
    ORDER BY Number
), Results AS
(
    SELECT f.Id, SUBSTRING(f.ID, t1.n, t2.n) numericvalues, 
         row_number() over (partition by f.Id 
                            order by LEN(SUBSTRING(f.ID, t1.n, t2.n)) desc) rn
    FROM NumbersTable t1
        INNER JOIN @foo AS f
            ON t1.n <= LEN(f.ID)
        INNER JOIN NumbersTable t2
            ON t2.n <= LEN(f.ID)
    WHERE SUBSTRING(f.ID, t1.n, t2.n) NOT LIKE '%[^0-9]%'
)
SELECT *
FROM Results
WHERE rn = 1

这将创建一个从1到40的数字表(因为这是您的最大长度),然后使用joins使用{{1}创建具有数值的数据的每个substring变体},然后根据该NOT LIKE '%[^0-9]%'的{​​{1}}建立一个row_number