SQL Server递归CTE未返回预期的行

时间:2018-04-24 12:51:14

标签: sql sql-server tsql recursion

我正在构建马尔可夫链名称生成器。我正在尝试用递归CTE替换while循环。在CTE的递归部分中使用toporder by的限制使我走上了以下道路。

所有这一切的要点是基于模型生成名称,这只是我将其分成三个字符段的另一个单词,存储在Markov_Model表的三列中。序列中的下一个字符将是Markov_Model中的字符,这样模型中的第1个和第2个字符与生成的单词中的倒数第二个字符和最终字符相匹配。我没有为第三个字符生成概率矩阵,而是使用标量函数找到符合条件的所有字符,并随机获取其中一个:order by newid()

问题在于,CTE的这种表达式在锚段中获得了所需的行数,但是从锚中递归调用CTE仅union一行的联合。我在底部附上了所需输出的样本。

查询:

;with names as 
(
    select top 5
        cast('+' as nvarchar(50)) as char1,
        cast('+' as nvarchar(50)) as char2,
        cast(char3 as nvarchar(50)) as char3,
        cast('++' + char3 as nvarchar(100)) as name_in_progress,
        1 as iteration
    from markov_Model
    where char1 is null
        and char2 is null
    order by newid()                 -- Get some random starting characters

    union all

    select
        n.char2 as char1,
        n.char3 as char2,
        cast(fnc.addition as nvarchar(50)) as char3,
        cast(n.name_in_progress + fnc.addition as nvarchar(100)),
        1 + n.iteration 
    from names n
    cross apply (
        -- This function takes the preceding two characters, 
        -- and gets a random character that follows the pattern
        select isnull(dbo.[fn_markov_getNext] (n.char2, n.char3), ',') as addition
    ) fnc
)
select * 
from names
option (maxrecursion 3)          -- For debug

问题是unionunion一行。

示例输出:

char1   char2   char3   name_in_progress    iteration
+       +       F       ++F                 1
+       +       N       ++N                 1
+       +       K       ++K                 1
+       +       S       ++S                 1
+       +       B       ++B                 1
+       B       a       ++Ba                2
B       a       c       ++Bac               3
a       c       h       ++Bach              4

注意我使用+,作为null替换符/分隔符。

我希望看到的是前一次递归的全部内容,并在name_in_progress中添加了新字符;每一次传球都应该完全修改前一次传球。

我想要的输出是:

enter image description here

Markov_Model表的前10位:

enter image description here

Markov_Model获取下一个字符的函数的文本:

CREATEFUNCTION [dbo].[fn_markov_getNext]
(
    @char2 nvarchar(1),
    @char3 nvarchar(1)
)
RETURNS nvarchar(1)
AS
BEGIN

    DECLARE @newChar nvarchar(1)

    set @newChar = (
        select top 1
            isnull(char3, ',')
        from markov_Model mm 
        where isnull(mm.char1, '+') = isnull(@char2, '+')
            and isnull(mm.char2, '+') = isnull(@char3, ',')
        order by (select new_id from vw_getGuid)    -- A view that calls newid()
    )

    return @newChar

END

0 个答案:

没有答案