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

时间:2019-07-17 14:24:47

标签: sql sql-server sql-update sql-server-2016

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

列值示例:

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|

3 个答案:

答案 0 :(得分:0)

您可以使用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) );

Demo

答案 1 :(得分:0)

Fiddle

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;

答案 2 :(得分:0)

说明:

一种可能的方法是使用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不能保证输出表中子字符串的顺序。

  

输出行可以按任何顺序排列。订单不保证   匹配输入字符串中子字符串的顺序。您可以   通过使用ORDER BY子句覆盖最终排序顺序   SELECT语句(ORDER BY值)。

在这种情况下,当每个子字符串的顺序很重要时,可以使用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