Załóżmy, że masz procedurę składowaną w tempdb:
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Istnieje dość zawiły sposób określania metadanych, które wygeneruje procedura składowana. Istnieje kilka zastrzeżeń, w tym procedura może wyprowadzić tylko jeden zestaw wyników, a jeśli nie można go dokładnie określić, zostanie dokonane najlepsze przypuszczenie, jeśli chodzi o typ danych. Wymaga użycia OPENQUERY
i serwer połączony z pętlą zwrotną z 'DATA ACCESS'
właściwość ustawiona na true. Możesz sprawdzić sys.servers, aby sprawdzić, czy masz już prawidłowy serwer, ale stwórzmy taki ręcznie o nazwie loopback
:
EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Teraz, gdy możesz zapytać o to jako serwer połączony, możesz użyć wyniku dowolnego zapytania (w tym wywołania procedury składowanej) jako zwykłego SELECT
. Możesz to zrobić (zwróć uwagę, że przedrostek bazy danych to ważne, w przeciwnym razie otrzymasz błąd 11529 i 2812):
SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Jeśli możemy wykonać SELECT *
, możemy również wykonać SELECT * INTO
:
SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
A kiedy już ta tabela #tmp istnieje, możemy określić metadane, mówiąc (zakładając, że SQL Server 2005 lub nowszy):
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');
(Jeśli używasz SQL Server 2000, możesz zrobić coś podobnego z kolumnami systemowymi, ale nie mam pod ręką instancji 2000 do sprawdzenia równoważnego zapytania).
Wyniki:
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
W Denali będzie to dużo, dużo, dużo łatwiejsze. Ponownie, nadal istnieje ograniczenie pierwszego zestawu wyników, ale nie musisz konfigurować połączonego serwera i przeskakiwać przez wszystkie te obręcze. Możesz po prostu powiedzieć:
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);
Wyniki:
name system_type_name
--------- ----------------
foo int
bar varchar(5)
Do czasu Denali sugeruję, że łatwiej byłoby po prostu zakasać rękawy i samodzielnie wymyślić typy danych. Nie tylko dlatego, że wykonywanie powyższych kroków jest żmudne, ale także dlatego, że jest znacznie bardziej prawdopodobne, że dokonasz poprawnego (lub przynajmniej dokładniejszego) odgadnięcia niż zrobi to silnik, ponieważ odgadnięcia typu danych, które wykonuje silnik, będą oparte na czasie wykonywania wyjście, bez żadnej zewnętrznej wiedzy o domenie możliwych wartości. Ten czynnik pozostanie również prawdziwy w Denali, więc nie miej wrażenia, że nowe funkcje odkrywania metadanych są ostateczne, po prostu sprawiają, że powyższe jest nieco mniej nużące.
Aha i kilka innych potencjalnych problemów z OPENQUERY
, zobacz artykuł Erlanda Sommarskoga tutaj:
http://www.sommarskog.se/share_data.html#OPENQUERY