使用 CTE 递归替换字符串

Recursively replace string using a CTE

我有 lookup_table 如下:-

|  id  | Val |
+------+-----+
|    1 | A   |
|   11 | B   |
|  111 | C   |
| 1111 | D   |

我正在使用 lookup_table 中的值创建单词,例如 $id!,并将其保存到另一个 table 中。 示例:差 - $11!$1!$1111!

所以我的 data_table 会是这样的,

|   expression    |
+-----------------+
| 1!!!    |         -- cab
| 11!!11! |         -- dad
| !!11!  |          -- bad

我想反向构建 data_table 中的单词。

我试过的:在$!上使用CHARINDEX从表达式中获取第一个id并尝试替换它使用 CTE 递归地匹配来自 look_up table 的 val。我没有得到我得到的确切结果,但通过一些 filetring,我得到了一些接近的结果。

我试过的查询

;WITH cte AS
  (SELECT  replace(expression,'$' + CONVERT(varchar(10),id) + '!' ,val) AS 'expression',
        cnt =1
   FROM data_table
   JOIN lookup_table ON id = 
        SUBSTRING(
            SUBSTRING(expression, CHARINDEX('$', expression) + 1, LEN(expression) - CHARINDEX('$', expression)), 1, CHARINDEX('!', expression) - 2) 
    UNION ALL 
    SELECT replace(expression,'$' + CONVERT(varchar(10),id) + '!' ,val) AS 'expression' ,
                 cnt = cnt +1
    FROM cte
    JOIN lookup_table ON id = 
        SUBSTRING(
            SUBSTRING(expression, CHARINDEX('$', expression) + 1, LEN(expression) - CHARINDEX('$', expression)), 1, CHARINDEX('!', expression) - (cnt +2))
    WHERE CHARINDEX('$', expression) > 0 )
SELECT expression
FROM cte
WHERE CHARINDEX('$', expression) = 0

当前输出:

| expression |
+------------+
| DAD        |
| CAB        |

预期输出:

| expression |
+------------+
| DAD        |
| CAB        |
| BAD        |

fiddle

我做错了什么?

编辑: fiddler 中的数据设置有错别字。 d 糟糕的是有五个 1 而不是四个。谢谢 DarkRob 指出。

你可以试试这个。您可以使用多个 cte 来创建表达式,而不是使用递归 cte。由于 sql 已经引入了这个 string_split 函数来将您的行单元格转换为特定分隔符上的行,这将使我们的工作变得更加容易。

首先,我们将每个单元格值转换为单独的行。此外,我们可以通过使用 inner join with lookup table 轻松获得我们的表达词。在最后一次使用东西时,我们将再次获得我们需要的字符串。

;WITH CTE AS (
    SELECT ROW_NUMBER() OVER (ORDER BY EXPRESSION) AS SLNO, * FROM data_table 
),
CT AS (
    SELECT *, REPLACE(VALUE,'$','') AS NEWVAL 
    FROM CTE CROSS APPLY string_split(EXPRESSION,'!')   WHERE VALUE <> ''
),
CTFINAL AS (
    SELECT * FROM CT INNER JOIN lookup_table AS LT ON CT.NEWVAL=LT.id
)
--SELECT * FROM CTFINAL
SELECT DISTINCT SLNO, 
    STUFF( (SELECT '' + VAL + '' FROM CTFINAL AS CFF WHERE CFF.SLNO=CF.SLNO FOR XML PATH('')), 1,0,'') AS MYVAL 
    FROM CTFINAL AS CF