Почему мы не можем использовать внешние соединения в рекурсивном CTE?

Рассмотрим ниже

;WITH GetParentOfChild AS
    (
        SELECT 
            Rn = ROW_NUMBER() Over(Order By (Select 1))
            ,row_id AS Parents
            ,parent_account_id  As ParentId 
        FROM siebelextract..account
        WHERE row_id = @ChildId
        UNION ALL
        SELECT 
            Rn + 1
            ,a.row_id as Parents
            ,a.parent_account_id As ParentId    
        FROM siebelextract..account a
        JOIN GetParentOfChild gp on a.row_id = gp.ParentId
    )

SELECT TOP 1 @ChildId = Parents 
FROM GetParentOfChild
ORDER BY Rn DESC

Что он делает, так это то, что для любого ребенка он вернет родительский корневой уровень... Программа отлично работает нормально все время...

Просто из любопытства/экспериментального саке я изменил JOIN на Left Outer Join, и он сообщил

Msg 462, уровень 16, состояние 1, процедура GetParent, строка 9 Внешнее соединение не допускается в рекурсивной части рекурсивного общего выражения таблицы GetParentOfChild.

Мой вопрос в том, почему рекурсивная часть CTE не может принять Left Outer Join? Это по дизайну?

Спасибо

Ответ 1

Да, это по дизайну, читайте Рекомендации по определению и использованию рекурсивных общих выражений таблицы

В CTE_query_definition рекурсивный член:

  • SELECT DISTINCT
  • GROUP BY
  • HAVING
  • Скалярная агрегация
  • TOP
  • LEFT, RIGHT, OUTER JOIN (INNER JOIN разрешено)
  • подзапросов

Обратите внимание, что если ваш запрос сделает левое соединение с ним через CTE, он может стать бесконечной рекурсией.

Ответ 2

Вы не можете использовать LEFT JOIN с рекурсивным CTE, но вы можете использовать OUTER APPLY, который должен давать те же результаты.