4

简而言之,我正在寻找一个可以对一个字符串执行多次替换的递归查询。我有一个想法可以做到,但我没能完全理解它。

当然,我更喜欢应用程序的 biz 层,甚至是 CLR,来进行替换,但在这种情况下,这些不是选项。

更具体地说,我想用 TVF 替换下面的混乱 - 这是 8 个不同存储过程中的 C&P。

SET @temp = REPLACE(RTRIM(@target), '~', '-')
SET @temp = REPLACE(@temp, '''', '-')
SET @temp = REPLACE(@temp, '!', '-')
SET @temp = REPLACE(@temp, '@', '-')
SET @temp = REPLACE(@temp, '#', '-')
-- 23 additional lines reducted
SET @target = @temp

这是我开始的地方:

-- I have a split string TVF called tvf_SplitString that takes a string 
-- and a splitter, and returns a table with one row for each element.
-- EDIT: tvf_SplitString returns a two-column table: pos, element, of which
--       pos is simply the row_number of the element.
SELECT REPLACE('A~B!C@D@C!B~A', MM.ELEMENT, '-') TGT
FROM   dbo.tvf_SplitString('~-''-!-@-#', '-') MM

请注意,我已将所有违规字符加入到一个由“-”分隔的单个字符串中(知道“-”永远不会成为违规字符之一),然后将其拆分。此查询的结果如下所示:

TGT
------------
A-B!C@D@C!B-A
A~B!C@D@C!B~A
A~B-C@D@C-B~A
A~B!C-D-C!B~A
A~B!C@D@C!B~A

所以,替换显然有效,但现在我希望它是递归的,所以我可以拉顶部 1 并最终得出:

TGT
------------
A-B-C-D-C-B-A

关于如何通过一个查询完成此操作的任何想法?

编辑:好吧,如果有另一种方法,则不需要实际的递归。我也在考虑在这里使用数字表。

4

2 回答 2

8

您可以在标量函数中使用它。我用它从一些外部输入中删除所有控制字符。

SELECT @target = REPLACE(@target, invalidChar, '-')
FROM (VALUES ('~'),(''''),('!'),('@'),('#')) AS T(invalidChar)
于 2016-01-26T02:48:43.260 回答
5

我想到了。我没有提到 tvf_SplitString 函数将行号返回为“pos”(尽管分配 row_number 的子查询也可以工作)。有了这个事实,我可以控制递归调用和拆分之间的交叉连接。

-- the cast to varchar(max) matches the output of the TVF, otherwise error.
-- The iteration counter is joined to the row number value from the split string
-- function to ensure each iteration only replaces on one character.
WITH XX AS (SELECT CAST('A~B!C@D@C!B~A' AS VARCHAR(MAX)) TGT, 1 RN
            UNION ALL
            SELECT REPLACE(XX.TGT, MM.ELEMENT, '-'), RN + 1 RN
            FROM   XX, dbo.tvf_SplitString('~-''-!-@-#', '-') MM
            WHERE  XX.RN = MM.pos)
SELECT TOP 1 XX.TGT  
FROM   XX
ORDER  BY RN DESC

不过,我对其他建议持开放态度。

于 2012-04-05T23:48:07.813 回答