提取两个分隔符之间的子字符串并输出到计算列中
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)
但是,如果您的值中没有 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);
同样,如果没有 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.
我目前在提取两个定界符之间的子字符串并将其输出到计算列时遇到问题。
我在名为 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)
但是,如果您的值中没有 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);
同样,如果没有 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.