提取两个分隔符之间的子字符串并输出到计算列中

Extract substring between two delimiters and output into calculated column

我目前在提取两个定界符之间的子字符串并将其输出到计算列时遇到问题。

我在名为 short_description 的列中有一些字符串如下所示:

"ABCD-0291 job SRT_FBEW_DNBADQAAGR in process published with status code 32"
"ABCD-0431 job DBDE_FKFW_MDNSQA in process published with status code 14"
"ABCD-0075 job SHFGF_RTBL_MJBVXW in process published with status code 19"

我基本上需要一种方法来提取第二个 space 之后但第三个 space 之前的部分。所以从查询返回的值应该是:

SRT_FBEW_DNBADQAAGR
DBDE_FKFW_MDNSQA
SHFGF_RTBL_MJBVXW

我知道带有 charindex 的子字符串可能是一种方法,但我不确定如何在我的特定示例中应用它,我们将不胜感激。

我试过这个代码:

Alter table Test_Data
Add substring_1 AS case when short description LIKE 'ABCD%' then 
LEFT(substring(short_description,
charindex(' ', short_description) +1, len(short_description)), charindex(' ', substring(short_description, charindex(' ', short_description) +2, len(short_description)))) end

但是输出returns“工作”不是我想要的。

一种方法是对 CHARINDEX 的几次嵌套调用。我在一些 VALUES 构造中这样做,以免需要重复调​​用:

SELECT SUBSTRING(V.YourColumn,CI2.I+1, CI3.I - CI2.I - 1) AS YourSubString
FROM (VALUES('ABCD-0291 job SRT_FBEW_DNBADQAAGR in process published with status code 32'),
            ('ABCD-0431 job DBDE_FKFW_MDNSQA in process published with status code 14'),
            ('ABCD-0075 job SHFGF_RTBL_MJBVXW in process published with status code 19'))V(YourColumn)
      CROSS APPLY (VALUES(CHARINDEX(' ',V.YourColumn)))CI1(I)
      CROSS APPLY (VALUES(CHARINDEX(' ',V.YourColumn,CI1.I + 1)))CI2(I)
      CROSS APPLY (VALUES(CHARINDEX(' ',V.YourColumn,CI2.I + 1)))CI3(I)

db<>fiddle

但是,如果您的值中没有 3 个空格,这将失败。


似乎 OP 实际上 想要将其作为计算列。我没有使用不同的解决方案,而是采用了上述方法,并将其转换为标量表达式:

ALTER TABLE dbo.YourTable ADD YourSubString AS SUBSTRING(YourColumn,CHARINDEX(' ',YourColumn,CHARINDEX(' ',YourColumn) + 1) + 1, CHARINDEX(' ',YourColumn,CHARINDEX(' ',YourColumn,CHARINDEX(' ',YourColumn) + 1) + 1) - CHARINDEX(' ',YourColumn,CHARINDEX(' ',YourColumn) + 1) - 1);

db<>fiddle

同样,如果没有 3 个空格,则会产生错误;我假设所有值都对源数据中的上述表达式有效。如果不是这种情况,我建议现在问一个新问题,因为目标帖子已经移动过一次。

您可以使用 STRING_SPLIT。问题是它 returns 是一个新的 table,所以我不确定它是否适合您的需要。尽管如此,以下代码仍然有效:

DECLARE @yourTable TABLE (
    colID int IDENTITY,
    yourString varchar(max)
)

INSERT  INTO @yourTable
VALUES  
    ('ABCD-0291 job SRT_FBEW_DNBADQAAGR in process published with status code 32'),
    ('ABCD-0431 job DBDE_FKFW_MDNSQA in process published with status code 14'),
    ('ABCD-0075 job SHFGF_RTBL_MJBVXW in process published with status code 19')

DECLARE @idColumn int
DECLARE @strToSubstr varchar(max)

SELECT @idColumn = MIN(colID) 
FROM @yourTable

WHILE @idColumn IS NOT NULL
BEGIN

    SELECT @strToSubstr = yourString 
    FROM @yourTable
    WHERE colID = @idColumn;

    WITH substrTable AS (
        SELECT ROW_NUMBER() OVER(ORDER BY (select 0)) AS RowNum, value 
        FROM STRING_SPLIT(@strToSubstr, ' ')
    )
    select value from substrTable
    where RowNum = 3;

    SELECT @idColumn = MIN(colID) 
    FROM @yourTable
    WHERE colID > @idColumn;
END

这里有一个潜在的想法:使用 STUFF 函数删除第一个 space,将第二个 space 替换为特殊字符并将第三个 space 替换为另一个特殊字符;然后使用 SUBSTRING 函数。

这是一个测试示例:

DECLARE @Value NVARCHAR(MAX) = 'ABCD-0291 job SRT_FBEW_DNBADQAAGR in process published with status code 32' 

SET @Value = STUFF(@Value, CHARINDEX(' ', @Value), 1, '')
SET @Value = STUFF(@Value, CHARINDEX(' ', @Value), 1, '~')
SET @Value = STUFF(@Value, CHARINDEX(' ', @Value), 1, '`')

SELECT SUBSTRING(@Value, CHARINDEX('~', @Value) + 1, CHARINDEX('`', @Value) - CHARINDEX('~', @Value) - 1)

我不知道上述想法的表现如何,但也许它能在某些方面有所帮助。

还记得它使用了2个特殊字符;这意味着在这些字符正常显示的情况下它无法正常工作,并且在其中没有 3 space 的情况下它也可能无法正常工作。

假设该值在字符串中不重复,可以使用string_split()加上一些比较得到第三个值:

select *
from t cross apply
     (select s.value
      from string_split(t.col, ' ') s
      where t.col like '% % ' + s.value + ' %' and
            t.col not like '% % % ' + s.value + ' %'
     ) s;

该值也有非常具体的形式,因此您可以查找:

select *
from t cross apply
     (select s.value
      from string_split(t.col, ' ') s
      where s.value like '%[_]%[_]%'
     ) s;

Here 是一个 db<>fiddle.