Использование: SQL SERVER 2016/2017
В настоящее время я использую sys.dm_exec_describe_first_result_set_for_object
для получения выходных определений для большого количества процедур. Я вижу некоторые неожиданные результаты, когда он запрашивает древовидную процедуру навигации. Я проследил, что проблема заключается в том, что встроенная процедура идентифицирует нулевые объекты в итерационных cte.
Код для тиражирования:
DROP TABLE IF EXISTS dbo.TestTable1;
DROP PROC IF EXISTS dbo.TestTableProc1;
DROP PROC IF EXISTS dbo.TestTableProc2;
CREATE TABLE dbo.TestTable1 (ParentID INT NOT NULL
, ChildID INT NOT NULL
, Guid UNIQUEIDENTIFIER NOT NULL);
GO
CREATE PROC dbo.TestTableProc1 (@Value1 INT)
AS
BEGIN;
WITH cte AS
(SELECT T1.ParentID
, T1.ChildID
, T1.Guid
FROM dbo.TestTable1 T1
WHERE T1.ParentID = @Value1
UNION ALL
SELECT T1.ParentID
, T1.ChildID
, T1.Guid
FROM dbo.TestTable1 T1)
SELECT cte.ParentID
, cte.ChildID
, cte.Guid
FROM cte;
END;
GO
CREATE PROC dbo.TestTableProc2 (@Value1 INT)
AS
BEGIN;
WITH cte AS
(SELECT T1.ParentID
, T1.ChildID
, T1.Guid
FROM dbo.TestTable1 T1
WHERE T1.ParentID = @Value1
UNION ALL
SELECT cte.ParentID
, cte.ChildID
, cte.Guid
FROM dbo.TestTable1 T1
JOIN cte ON T1.ParentID = cte.ChildID)
SELECT cte.ParentID
, cte.ChildID
, cte.Guid
FROM cte;
END;
GO
SELECT 'dbo.TestTableProc1'
, name
, is_nullable
FROM sys.dm_exec_describe_first_result_set_for_object(OBJECT_ID('dbo.TestTableProc1'), 0)
UNION ALL
SELECT 'dbo.TestTableProc2'
, name
, is_nullable
FROM sys.dm_exec_describe_first_result_set_for_object(OBJECT_ID('dbo.TestTableProc2'), 0);
DROP PROC IF EXISTS dbo.TestTableProc1;
DROP PROC IF EXISTS dbo.TestTableProc2;
DROP TABLE IF EXISTS dbo.TestTable1;
Это дает набор результатов:
Как видно из результатов TestTableProc1
правильно идентифицирует все поля как ненулевые. Где, как TestTableProc2
идентифицирует все поля как обнуляемые, которыми они никогда не будут.
В качестве решения этой проблемы я могу переместить весь процесс в подпроцедуру, а затем вызвать подпрограмму с текущим именем и добавить предложение WITH RESULTSET
, чтобы заблокировать вывод. Хотя это функциональный обходной путь, это означало бы снижение производительности и добавление дополнительных процедур в базу данных, где они не требуются.
Мне нужен способ получить правильное описание набора результатов, так как это редкий вызов, и я могу немного снизить производительность, вместо того, чтобы изменять саму основную процедуру.
Любые варианты с благодарностью получены.