从列中选择子字符串,但每条记录都有不同的模式

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 的多个值?

使用正则表达式从 mysql 列中提取子字符串

PANDAS 从列中找到确切的给定字符串/单词

SQL查询以选择在同一列中具有不同值的子记录的父级

Python Dataframe:DF列中的字符串包含来自不同DF的子字符串和匹配时返回的子字符串值

从字段 sql/presto 中提取子字符串