Така че да кажем, че имате съхранена процедура в tempdb:
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Има доста сложен начин, по който можете да определите метаданните, които съхранената процедура ще изведе. Има няколко предупреждения, включително процедурата може да изведе само един набор от резултати и че ще бъде направено най-добро предположение за типа данни, ако не може да бъде определен точно. Това изисква използването на OPENQUERY
и свързан сървър с обратна връзка с 'DATA ACCESS'
свойството е зададено на true. Можете да проверите sys.servers, за да видите дали вече имате валиден сървър, но нека просто създадем такъв ръчно наречен loopback
:
EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Сега, когато можете да заявите това като свързан сървър, можете да използвате резултата от всяка заявка (включително извикване на съхранена процедура) като обикновен SELECT
. Така че можете да направите това (обърнете внимание, че префиксът на базата данни е важно, в противен случай ще получите грешка 11529 и 2812):
SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Ако можем да изпълним SELECT *
, можем също да извършим SELECT * INTO
:
SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
И след като тази таблица #tmp съществува, можем да определим метаданните, като кажем (ако приемем SQL Server 2005 или по-нова):
SELECT c.name, [type] = t.name, c.max_length, c.[precision], c.scale
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE c.[object_id] = OBJECT_ID('tempdb..#tmp');
(Ако използвате SQL Server 2000, можете да направите нещо подобно с syscolumns, но нямам удобен екземпляр 2000 за валидиране на еквивалентна заявка.)
Резултати:
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
В Денали това ще бъде много, много, много по-лесно. Отново все още има ограничение на първия набор от резултати, но не е нужно да настройвате свързан сървър и да прескачате през всички тези обръчи. Можете просто да кажете:
DECLARE @sql NVARCHAR(MAX) = N'EXEC tempdb.dbo.my_procedure;';
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set(@sql, NULL, 1);
Резултати:
name system_type_name
--------- ----------------
foo int
bar varchar(5)
До Denali, предлагам да бъде по-лесно просто да запретнете ръкави и да разберете типовете данни сами. Не само защото е досадно да преминавате през горните стъпки, но и защото е много по-вероятно да направите правилно (или поне по-точно) предположение, отколкото двигателят, тъй като типът данни предполага, че двигателят прави, ще се основава на времето на изпълнение изход, без никакви външни познания за областта на възможните стойности. Този фактор ще остане верен и в Denali, така че не оставайте с впечатлението, че новите функции за откриване на метаданни са крайни, те просто правят горното малко по-малко досадно.
О, и за някои други потенциални проблеми с OPENQUERY
, вижте статията на Erland Sommarskog тук:
http://www.sommarskog.se/share_data.html#OPENQUERY