我正在构建马尔可夫链名称生成器。我正在尝试用递归CTE替换while
循环。在CTE的递归部分中使用top
和order 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
问题是union
仅union
一行。
示例输出:
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
中添加了新字符;每一次传球都应该完全修改前一次传球。
我想要的输出是:
Markov_Model
表的前10位:
从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