Рекурсивный вызов МОЖЕТ быть очень полезной функцией, особенно когда вы выводите XML, и вам нужно получить дочерние узлы XML, которые имеют равный по формату родительский узел. Обходной путь - использование хранимых процедур для обработки родительских / дочерних отношений с недостатком более сложного / избыточного кода. Скажем, у вас есть:
create table Users (UserID int, Name nvarchar(50), ManagerID int null)
insert into Users (1, 'Carl', null)
insert into Users (2, 'Tom', 1)
insert into Users (3, 'John', 1)
и
create function GetUser(@UserID int)
returns XML as
begin
declare @xml XML
SET @xml = (
SELECT [UserID] "User/@UserID"
, [Name] "User/@Name"
FROM Users
WHERE [UserID] = @UserID
FOR XML PATH(''), TYPE
)
return @xml
end
Чтобы получить все менеджеры в XML:
create proc GetAllManagers() as
begin
set nocount on;
SELECT dbo.GetUser([UserID])
FROM Users
WHERE [ManagerID] IS NULL
FOR XML PATH(''), TYPE, root('Managers')
end
Теперь к проблеме. Что если для каждого менеджера я хочу, чтобы все пользователи принадлежали менеджеру? Я хотел бы, чтобы моя функция могла вызывать сама себя:
alter function GetUser(@UserID int, @IsIncludeChildren bit)
returns XML as
begin
declare @xml XML
SET @xml = (
SELECT [UserID] "User/@UserID"
, [Name] "User/@Name"
, (SELECT dbo.GetUser([UserID], 0)) "User/Children"
FROM Users
WHERE [ManagerID] = @UserID AND @IsIncludeChildren = 1
FOR XML PATH(''), TYPE
)
return @xml
end
и называя это просто
alter proc GetAllManagers() as
begin
set nocount on;
SELECT dbo.GetUser([UserID], 1)
FROM Users
WHERE [ManagerID] IS NULL
FOR XML PATH(''), TYPE, root('Managers')
end
Но это невозможно из-за лимита вложенности. Итак, обходной путь (с использованием первой функции):
alter proc GetAllManagers() as
begin
set nocount on;
SELECT
dbo.GetUser([UserID])
, (
SELECT dbo.GetUser([UserID])
FROM Users
WHERE [ManagerID] = [Users].[UserID]
FOR XML PATH(''), TYPE
) "User/Children"
FROM Users as [Users]
WHERE [ManagerID] IS NULL
FOR XML PATH(''), TYPE, root('Managers')
end
Это не так уж плохо, но если у вас есть множество других процедур, возвращающих пользовательские данные, вам придется строить отношения родитель / потомок во всех процессах, а не в одной функции!
Итак, Microsoft, исправь это!