简而言之,我正在寻找一个可以在一个字符串上执行多次替换的递归查询。我有一个可以做到的想法,但我没能绕过它。
当然,我更喜欢应用程序的商业层,甚至是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
有关如何使用一个查询完成此操作的任何想法?
编辑:嗯,如果有另一种方式,实际的递归是不必要的。我也在考虑在这里使用数字表。答案 0 :(得分:4)
我明白了。我没有提到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
不过,我仍然愿意接受其他建议。
答案 1 :(得分:4)
您可以在标量函数中使用它。我用它从一些外部输入中删除所有控制字符。
SELECT @target = REPLACE(@target, invalidChar, '-')
FROM (VALUES ('~'),(''''),('!'),('@'),('#')) AS T(invalidChar)