我需要一个T-SQL查询来获得涵盖所有情况的输出(以下在预期中指定)。我尝试这样做,但未成功:
select
code,
substring(code, patindex('%[0-9]%', code),
case
when patindex('%[. ,/-]%', substring(code, patindex('%[0-9]%', code), len(code))) <> 0
then patindex('%[. ,/-]%', substring(code, patindex('%[0-9]%', code), len(code))) - 1
else patindex('%[. ,/-]%', substring(code, patindex('%[0-9]%', code), len(code)))
end)
from
table
这是预期的输出
input output
------------------------------------------------------
AB 123456.123 123456
AB 123456/123 123456
AB 123456-123 123456
AB B0-23456.123 0-23456
AB 1234 5678 9545 3214.123 1234 5678 9545 3214
AB 123456 123 123456
AB.123456 123 123456
AB..123456 123 123456
AB..1C23456 123 1C23456
规则
答案 0 :(得分:2)
我相信这将满足您的所有条件,但请务必对照此处未介绍的极端情况进行检查,以确保它符合您的期望。
DECLARE @table as TABLE (code VARCHAR(40))
INSERT INTO @table
(code)
Values
('AB 123456.123'),
('AB 123456/123'),
('AB 123456-123'),
('AB B0-23456.123'),
('AB 1234 5678 954 3214.123'),
('AB 1234 5678 9545/3214.123'),
('AB 123456 123'),
('AB.123456 123'),
('AB..123456 123'),
('AB..1C23456 123')
SELECT
code as [input],
SUBSTRING(code,PATINDEX('%[0-9]%', code),
CASE WHEN PATINDEX('%[ -][0-9][0-9][0-9][0-9]%',SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code))) <> 0
THEN
CASE WHEN PATINDEX('%[.,/]%',SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code))) < ISNULL(NULLIF(PATINDEX('%[ -][0-9][0-9][0-9][^0-9]%',SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code))),0),LEN(code))
THEN PATINDEX('%[.,/]%',SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code)))-1
ELSE ISNULL(NULLIF(PATINDEX('%[ -][0-9][0-9][0-9][^0-9]%',SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code))),0),LEN(code))
END
ELSE PATINDEX('%[. ,/-]%', SUBSTRING(code,PATINDEX('%[0-9]%', code),LEN(code)))-1
END
) as [output]
FROM @table
编辑:修改内部案例陈述以纠正注释中提到的边缘案例,只是为了证明这可以在不使用CTE的情况下完成。 :)
答案 1 :(得分:1)
说实话:这是一场噩梦。 T-SQL
绝对是错误的工具!
仅因为我没有提供足够的答案(由于您的问题不足够),我还是被要求以某种方式解决此问题。这是体育精神的问题...
DECLARE @mockup TABLE(ID INT IDENTITY, YourString VARCHAR(1000));
INSERT INTO @mockup VALUES
('AB 123456.123')
,('AB 123456/123')
,('AB 123456-123')
,('AB B0-23456.123')
,('AB 1234 5678 9545 3214.123')
,('AB 123456 123')
,('AB.123456 123')
,('AB..123456 123')
,('AB..1C23456 123')
,('AB 1234 5678 954 3214-12345.123');
-噩梦
WITH CutForRules AS
(
SELECT t.ID
,t.YourString
,ROW_NUMBER() OVER(PARTITION BY t.ID ORDER BY (SELECT (NULL))) FragmentIndex
,c AsXml
,d.value('text()[1]','varchar(100)') Fragment
,ISNUMERIC(d.value('text()[1]','varchar(100)')) FragmentIsNum
,LEN(d.value('text()[1]','varchar(100)')) FragmentLength
,d.value('@dlmt','varchar(10)') Delimiter
FROM @mockup t
CROSS APPLY(SELECT REVERSE(SUBSTRING(t.YourString,PATINDEX('%[0-9]%',t.YourString),1000))) A(a)
CROSS APPLY(SELECT REVERSE(SUBSTRING(a,PATINDEX('%[ /.-]%',a)+1,1000))) B(b)
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(b,'/','|'),' ','</x><x dlmt=" ">'),'.','</x><x dlmt=".">'),'-','</x><x dlmt="-">'),'|','</x><x dlmt="/">') + '</x>' AS XML)) C(c)
CROSS APPLY c.nodes('/x') D(d)
)
SELECT t1.ID
,t1.YourString
,(
SELECT CONCAT(t2.Delimiter,t2.Fragment)
FROM CutForRules t2
WHERE t1.ID=t2.ID
AND (t2.FragmentIndex<(SELECT MIN(t3.FragmentIndex)
FROM CutForRules t3
WHERE t3.ID=t1.ID
AND t3.FragmentIndex>t2.FragmentIndex
AND t3.Delimiter=' '
AND t3.FragmentLength<4
AND t3.FragmentIsNum=1)
OR NOT EXISTS(SELECT 1 FROM CutForRules t4 WHERE t4.ID=t1.ID AND t4.Delimiter=' ' AND t4.FragmentLength<4)
)
ORDER BY t2.FragmentIndex
FOR XML PATH('')
)
FROM CutForRules t1
GROUP BY t1.ID,t1.YourString
ORDER BY t1.ID;
您可以放置一个SELECT * FROM CutForRules
来查看我为此使用的中间结果集。
但是我很确定,您会想出哦,可以,但是还有另外一种情况……
只需弄清楚一点:我在这一点上;;)
CTE CutForRules 会为我的测试数据返回此设置:
+----+---------------------------------+---------+---+---+------+
| | YourString |Fragment | N | L | Delm |
+----+---------------------------------+---------+---+---+------+
| 1 | AB 123456.123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 2 | AB 123456/123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 3 | AB 123456-123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 4 | AB B0-23456.123 | 0 | 1 | 1 | NULL |
+----+---------------------------------+---------+---+---+------+
| 4 | AB B0-23456.123 | 23456 | 1 | 5 | - |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 1234 | 1 | 4 | NULL |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 5678 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 9545 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 5 | AB 1234 5678 9545 3214.123 | 3214 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 6 | AB 123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 7 | AB.123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 8 | AB..123456 123 | 123456 | 1 | 6 | NULL |
+----+---------------------------------+---------+---+---+------+
| 9 | AB..1C23456 123 | 1C23456 | 0 | 7 | NULL |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 1234 | 1 | 4 | NULL |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 5678 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 954 | 1 | 3 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 3214 | 1 | 4 | |
+----+---------------------------------+---------+---+---+------+
| 10 | AB 1234 5678 954 3214-12345.123 | 12345 | 1 | 5 | - |
+----+---------------------------------+---------+---+---+------+
提供的SELECT
将按ID,YourString
分组。这意味着:每个ID 1行。
返回的列是分组列加上一个很大的计算列。
这是与相关的子查询。它将获取当前ID的所有行并进行处理。然后返回其结果FOR XML PATH
,这是将所有结果连接在一起的一个技巧。
棘手的部分在WHERE
中:如果在长度为<4
的空格之后至少有一个数字片段,则字符串将不包括该片段和所有后续片段。
如何获取当前元素之前的元素?
这又是一个关联子查询,它以比当前元素大FragmentIndex
的方式提取ID组中的元素。