从列中选择子字符串,但每条记录都有不同的模式
Posted
技术标签:
【中文标题】从列中选择子字符串,但每条记录都有不同的模式【英文标题】:Select substring from column but each record has different pattern 【发布时间】:2021-10-30 13:53:25 【问题描述】:对于每条记录,我都有具有不同字符串模式的列,我们称之为 [描述]。这是记录示例
[Description]
-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532
-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234
-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A
我只想选择最后一个数字顺序 - 所以输出将是:
[Description]
-11000532
-11001234
-21001123
有什么函数怎么获取?
谢谢
【问题讨论】:
根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。 提问时,您需要提供minimal reproducible example: (1) DDL 和样本数据填充,即 CREATE 表和 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上面#1 中的样本数据。 (4) 您的 SQL Server 版本 (SELECT @@version;)。 【参考方案1】:您的示例很棘手,因为它也将字母作为订单号的一部分。
我假设您的数据类型是 VARCHAR(4000),因此,我在最后应用了 4000 的子字符串,以使其更简单。
DECLARE @table table(Description varchar(4000))
insert into @table values
('-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532')
,('-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A')
,('-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234');
SELECT SUBSTRING(REVERSE(SUBSTRING(REVERSE(Description),1,CHARINDEX('+',REVERSE(Description)))),PATINDEX('%[1-9]%',REVERSE(SUBSTRING(REVERSE(Description),1,CHARINDEX('+',REVERSE(Description))))),4000) as ordernumber FROM @table
ordernumber |
---|
11000532 |
21001123A |
11001234 |
【讨论】:
干草 @venkataraman 感谢您的帮助。您的代码几乎是正确的,但第二行仍然有 'A' 字符。我期望所有数字只是因为目标列是整数数据类型。 @Paktelo,所以,你想替换订单号中的任何字母 是的,只是数字【参考方案2】:请尝试以下解决方案。
第一个解决方案适用于 SQL Server 2017 及更高版本。
它通过执行以下步骤来工作:
-
它将列值标记为 XML。
最后一个令牌是我们的目标,即
(/root/r[last()]/text())[1]
TRIM() 删除不需要的字符。
第二个解决方案是针对 SQL Server 2012。它涉及的更多。
SQL 2017
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Tokens VARCHAR(4000));
INSERT INTO @tbl VALUES
('-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532'),
('-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A'),
('-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = '+'
, @CharsToRemove VARCHAR(100) = 'AZ';
SELECT ID, tokens
, TRIM(@CharsToRemove FROM token) AS Result
FROM @tbl
CROSS APPLY (VALUES (TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML))) AS t(c)
CROSS APPLY (VALUES (c.value('(/root/r[last()]/text())[1]', 'VARCHAR(256)'))) AS t2(token);
SQL 2012
SELECT ID, tokens
, (
SELECT SUBSTRING(token, number, 1)
FROM @tbl AS c
CROSS APPLY (
SELECT DISTINCT number
FROM master..spt_values
WHERE number BETWEEN 1 AND LEN(token)
) V
WHERE c.ID = p.ID
FOR XML PATH('r'), TYPE, ROOT('root')
)
.query('for $x in /root/r
return if (xs:int($x) instance of xs:int) then $x
else ()')
.query('/r/text()').value('.', 'BIGINT') AS Result
FROM @tbl AS p
CROSS APPLY (VALUES (TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML))) AS t(c)
CROSS APPLY (VALUES (c.value('(/root/r[last()]/text())[1]', 'VARCHAR(256)'))) AS t2(token);
输出
+----+---------------------------------------------------------------------+----------+
| ID | tokens | Result |
+----+---------------------------------------------------------------------+----------+
| 1 | -qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532 | 11000532 |
| 2 | -qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A | 21001123 |
| 3 | -qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234 | 11001234 |
+----+---------------------------------------------------------------------+----------+
【讨论】:
以上是关于从列中选择子字符串,但每条记录都有不同的模式的主要内容,如果未能解决你的问题,请参考以下文章
如何在子查询的 WHERE 子句中使用来自 UNNEST 的多个值?