更新 SQL Server 中分隔符之间包含的字符串的一部分



我必须更新一个文本列,该列是由|分隔的字符串列表。我想用空文本替换第二个字符串。

列值示例:

TD_DM_U100|BK_U100|TL_DM_U100||||
TD_DM_U200|BK_U200|TL_DM_L100||SOME TEXT||
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT|

更新后的结果(删除第二个字符串)

TD_DM_U100||TL_DM_U100||||
TD_DM_U200||TL_DM_L100||SOME TEXT||
TD_DM_U300||TL_DM_L100||SOME TEXT|MORE TEXT|

您可以使用charindex()substring()函数的贡献进行更新

update tab
set col = replace(col,substring(col,charindex('|', col),len(col)),'||')+
substring( substring(col,charindex('|', col),len(col)), 
charindex('|', col),len(col) );

演示

小提琴

SET NOCOUNT ON;
GO
DECLARE
@val VARCHAR(MAX);
DECLARE
@TestData TABLE
(
Id INT IDENTITY (1, 1),
Col1 VARCHAR(100)
);
DECLARE
@i INT = 1;
INSERT INTO @TestData
VALUES
(
'TD_DM_U100|BK_U100|TL_DM_U100||||'
),
(
'TD_DM_U200|BK_U200|TL_DM_L100||SOME TEXT||'
),
(
'TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT|'
);
DECLARE
@Result TABLE
(
Col1 VARCHAR(100)
);
WHILE @i <=
(
SELECT
COUNT(*)
FROM
@TestData
)
BEGIN
SET @val = NULL;
SELECT
@val = COALESCE(@val + '| ' + v.Col1, v.Col1)
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY
(
SELECT
1
)
) rn,
value
FROM
STRING_SPLIT(
(
SELECT
Col1
FROM
@TestData
WHERE
Id = @i
)
, '|')
) t1
CROSS APPLY
(
SELECT
CASE
WHEN rn = 2 THEN ''
ELSE value
END
) v (Col1);

INSERT INTO @Result
SELECT
@val;
SET @i += 1;
END;
SELECT
*
FROM
@Result;

解释:

一种可能的方法是使用LEFTRIGHTCHARINDEXLEN函数来解析和操作文本值。下一条语句演示了此方法:

-- Statement
DECLARE @Text varchar(max) = 'A|B|C|D|'
SELECT 
LEFT(@Text, CHARINDEX('|', @Text)) AS LeftPart,
RIGHT(@Text, LEN(@Text) - CHARINDEX('|', @Text)) AS RightPart
-- Output
LeftPart RightPart
A|       B|C|D|

溶液:

在您的情况下,因为您需要更改文本的第二部分,因此语句会更复杂:

桌子:

CREATE TABLE #Data (
[Text] varchar(max)
)
INSERT INTO #Data
([Text])
VALUES
('TD_DM_U100|BK_U100|TL_DM_U100||||'),
('TD_DM_U200|BK_U200|TL_DM_L100||SOME TEXT||'),
('TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT|')

陈述:

UPDATE #Data
SET [Text] = CONCAT(
LEFT([Text], CHARINDEX('|', [Text])),
'|',  -- Or use some different value
RIGHT(RIGHT([Text], LEN([Text]) - CHARINDEX('|', [Text])), LEN(RIGHT([Text], LEN([Text]) - CHARINDEX('|', [Text]))) - CHARINDEX('|', RIGHT([Text], LEN([Text]) - CHARINDEX('|', [Text]))))
)

输出:

SELECT *
FROM #Data
--------------------------------------------
Text
--------------------------------------------
TD_DM_U100||TL_DM_U100||||
TD_DM_U200||TL_DM_L100||SOME TEXT||
TD_DM_U300||TL_DM_L100||SOME TEXT|MORE TEXT|

笔记:

作为附加信息,另一种可能的方法是将每个文本转换为表格,更新此表中的行,然后将表格的行聚合为文本。SQL Server 支持STRING_SPLIT(来自 SQL Server 2016)和STRING_AGG(来自 SQL Server 2017)功能,但在您的特定情况下,这不是一个选项。原因是,STRING_SPLIT不能保证输出表中子字符串的顺序。

输出行可以按任意顺序排列。订单不保证 匹配输入字符串中子字符串的顺序。您可以 通过在 选择语句(按值排序)。

在这种情况下,当每个子字符串的顺序很重要时,可以使用JSONXML转换。下一个基本示例使用JSON功能演示了这一点:

-- Statement
DECLARE @Text nvarchar(max) = N'TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT|'
SELECT 
@Text AS [Text],
j.[key] + 1 AS Position,
j.[value]
FROM OPENJSON(CONCAT(N'["', REPLACE(@Text, '|', '","'), N'"]')) j
-- Output
Text                                                Position value
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 1        TD_DM_U300
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 2        BK_U300
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 3        TL_DM_L100
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 4   
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 5        SOME TEXT
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 6        MORE TEXT
TD_DM_U300|BK_U300|TL_DM_L100||SOME TEXT|MORE TEXT| 7   

最新更新