【问题标题】:Recursive replace from a table of characters从字符表递归替换
【发布时间】:2012-04-19 16:46:05
【问题描述】:

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

当然,我更喜欢应用程序的 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

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

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

【问题讨论】:

    标签: tsql sql-server-2005 recursion


    【解决方案1】:

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

    SELECT @target = REPLACE(@target, invalidChar, '-')
    FROM (VALUES ('~'),(''''),('!'),('@'),('#')) AS T(invalidChar)
    

    【讨论】:

    • 这比我提供的复杂递归 CTE 要好得多。我认为 SQL 会为 T 中的每一行重新评估 @target 的值并不明显,尽管它确实很有意义。
    【解决方案2】:

    我想通了。我没有提到 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
    

    不过,我愿意接受其他建议。

    【讨论】:

      猜你喜欢
      • 2011-09-27
      • 2016-04-09
      • 2011-05-09
      • 1970-01-01
      • 2017-04-24
      • 2020-11-05
      • 1970-01-01
      • 2011-10-28
      • 2013-08-21
      相关资源
      最近更新 更多