Я создаю марковский генератор имен цепей. Я пытаюсь заменить цикл while
рекурсивным CTE. Ограничения в использовании top
и order by
в рекурсивной части CTE привели меня к следующему пути.
Смысл всего этого состоит в том, чтобы генерировать имена на основе модели, которая является еще одним словом, которое я разбил на три сегмента символов, хранящихся в трех столбцах таблицы Markov_Model
. Следующим символом в последовательности будет символ из Markov_Model
, так что 1-й и 2-й символы в модели соответствуют предпоследнему и последнему символу в генерируемом слове. Вместо того, чтобы генерировать матрицу вероятностей для этого третьего символа, я использую скалярную функцию, которая находит все символы, которые соответствуют критериям, и получает один из них случайным образом: order by newid()
.
Проблема в том, что эта формулировка CTE получает желаемое количество строк в сегменте привязки, но объединение, которое рекурсивно вызывает CTE, только union
s на одну строку из привязки. Я прикрепил образец желаемого выхода внизу.
Запрос:
;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
; каждый проход должен полностью изменить предыдущий проход.
Мой желаемый результат будет:

Топ 10 таблицы Markov_Model
:

Текст функции, которая получает следующий символ из 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