[Току-що разбрах, че съм отговарял на този въпрос преди]
Правенето на това за съхранена процедура е много по-сложно, отколкото за изглед или таблица. Един от проблемите е, че една съхранена процедура може да има множество различни кодови пътища в зависимост от входните параметри и дори неща, които не можете да контролирате като състояние на сървъра, време от деня и т.н. Така например какво бихте очаквали да видите като изход за тази съхранена процедура? Ами ако има множество набори от резултати, независимо от условните?
CREATE PROCEDURE dbo.foo
@bar INT
AS
BEGIN
SET NOCOUNT ON;
IF @bar = 1
SELECT a, b, c FROM dbo.blat;
ELSE
SELECT d, e, f, g, h FROM dbo.splunge;
END
GO
Ако вашата съхранена процедура няма кодови пътища и сте уверени, че винаги ще виждате един и същ набор от резултати (и можете да определите предварително какви стойности трябва да бъдат предоставени, ако съхранената процедура има незадължителни параметри), нека вземем прост пример:
CREATE PROCEDURE dbo.bar
AS
BEGIN
SET NOCOUNT ON;
SELECT a = 'a', b = 1, c = GETDATE();
END
GO
FMTONLY
Един от начините е да направите нещо подобно:
SET FMTONLY ON;
GO
EXEC dbo.bar;
Това ще ви даде празен набор от резултати и вашето клиентско приложение може да разгледа свойствата на този набор от резултати, за да определи имената на колони и типове данни.
Сега има много проблеми с SET FMTONLY ON;
че няма да навлизам тук, но най-малкото трябва да се отбележи, че тази команда е отхвърлена - по основателна причина. Също така внимавайте да SET FMTONLY OFF;
когато сте готови, или ще се чудите защо сте създали съхранена процедура успешно, но след това не можете да я изпълните. И не, не ви предупреждавам за това, защото просто ми се случи. Честен. :-)
ОТКРИВАНЕ
Като създадете свързан сървър с обратна връзка, можете да използвате инструменти като OPENQUERY
за да изпълните съхранена процедура, но да върнете композируем набор от резултати (добре, моля, приемете това като изключително хлабава дефиниция), която можете да проверите. Първо създайте loopback сървър (това предполага локален екземпляр с име FOO
):
USE master;
GO
EXEC sp_addlinkedserver @server = N'.\FOO', @srvproduct=N'SQL Server'
GO
EXEC sp_serveroption @server=N'.\FOO', @optname=N'data access',
@optvalue=N'true';
Сега можем да вземем процедурата по-горе и да я вкараме в заявка като тази:
SELECT * INTO #t
FROM OPENQUERY([.\FOO], 'EXEC dbname.dbo.bar;')
WHERE 1 = 0;
SELECT c.name, t.name
FROM tempdb.sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
WHERE c.[object_id] = OBJECT_ID('tempdb..#t');
Това игнорира типове псевдоними (по-рано известни като потребителски дефинирани типове данни) и също така може да покаже два реда за колони, дефинирани като например sysname
. Но от горното се получава:
name name
---- --------
b int
c datetime
a varchar
Очевидно има още работа тук - varchar
не показва дължина и ще трябва да получите точност/мащаб за други типове, като datetime2
, time
и decimal
. Но това е начало.
SQL Server 2012
Има някои нови функции в SQL Server 2012, които правят откриването на метаданни много по-лесно. За горната процедура можем да направим следното:
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
OBJECT_ID('dbo.bar'),
NULL
);
Наред с други неща, това всъщност осигурява прецизност и мащаб и разрешава типове псевдоними за нас. За горната процедура това дава:
name system_type_name
---- ----------------
a varchar(1)
b int
c datetime
Няма голяма разлика визуално, но когато започнете да навлизате във всички различни типове данни с различна точност и мащаб, ще оцените допълнителната работа, която тази функция върши за вас.
Недостатъкът:в SQL Server 2012 поне тези функции работят само за първия набор от резултати (както подсказва името на функцията).