如何限制 CTE 中的 STUFF 函数以删除重复单词前的字符

How to limit STUFF function within CTE for removing character before recurring word

的跟进问题

以下代码归功于@Larnu,如果重复单词“[BACKSPACE]”之前不再有字符,如何修改此代码以不生成空值。我相信空值的出现是因为 CHARINDEX() 函数在重复出现的 [BACKSPACE] 单词之前不再有字符时产生负值。该解决方案需要与 SQL Server 2008 兼容。

最终目标是凡是有[BACKSPACE]的地方,如果[BACKSPACE]前面有字符,就去掉;否则,不要尝试删除之前的字符。

DECLARE @inputString NVARCHAR(MAX);

SET @inputString = 'Word[BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE]sgred[BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE]SecondWord';

WITH rCTE AS(
    SELECT V.YourColumn,
           STUFF(V.YourColumn,CHARINDEX('[BACKSPACE]',V.YourColumn)-1,LEN('[BACKSPACE]')+1,'') AS ReplacedColumn,
           1 AS Iteration
    FROM (VALUES(@inputString))V(YourColumn)
    UNION ALL
    SELECT r.YourColumn,
           STUFF(r.ReplacedColumn,CHARINDEX('[BACKSPACE]',r.ReplacedColumn)-1,LEN('[BACKSPACE]')+1,''),
           r.Iteration + 1
    FROM rCTE r
    WHERE CHARINDEX('[BACKSPACE]',r.ReplacedColumn) > 0)
SELECT TOP (1) WITH TIES
       r.YourColumn,
       r.ReplacedColumn
FROM rCTE r
ORDER BY ROW_NUMBER() OVER (PARTITION BY r.YourColumn ORDER BY r.Iteration DESC);

期望的输出是'SecondWord'

你需要CASE检查你是否在字符串的开头,在这种情况下你不需要前面的位置,因为那是0.

我会对这段代码做一些其他改进:LEN 可以计算一次,我们也可以将 [BACKSPACE] 值存储在一个变量中

DECLARE @inputString NVARCHAR(MAX);

SET @inputString = 'Word[BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE]sgred[BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE]SecondWord';

DECLARE @bspace nvarchar(50) = '[BACKSPACE]';
DECLARE @len int = LEN(@bspace);

WITH rCTE AS(
    SELECT V.YourColumn,
           STUFF(V.YourColumn,CHARINDEX(@bspace,V.YourColumn)-1,@len+1,'') AS ReplacedColumn,
           1 AS Iteration
    FROM (VALUES(@inputString))V(YourColumn)
    UNION ALL
    SELECT r.YourColumn,
           CASE WHEN CHARINDEX(@bspace,r.ReplacedColumn) = 1
             THEN STUFF(r.ReplacedColumn,1,@len,'')
             ELSE STUFF(r.ReplacedColumn,CHARINDEX(@bspace,r.ReplacedColumn)-1,@len+1,'')
           END,
           r.Iteration + 1
    FROM rCTE r
    WHERE CHARINDEX(@bspace,r.ReplacedColumn) > 0)
SELECT TOP (1) WITH TIES
       r.YourColumn,
       r.ReplacedColumn
FROM rCTE r
ORDER BY ROW_NUMBER() OVER (PARTITION BY r.YourColumn ORDER BY r.Iteration DESC);