Så lad os sige, at du har en lagret procedure i tempdb:
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Der er en ret indviklet måde, hvorpå du kan bestemme de metadata, som den lagrede procedure vil udlæse. Der er flere forbehold, herunder proceduren kan kun udskrive et enkelt resultatsæt, og at der vil blive lavet et bedste gæt om datatypen, hvis den ikke kan bestemmes præcist. Det kræver brug af OPENQUERY
og en loopback-linket server med 'DATA ACCESS'
egenskab sat til sand. Du kan tjekke sys.servers for at se, om du allerede har en gyldig server, men lad os bare oprette en manuelt kaldet loopback
:
EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Nu hvor du kan forespørge om dette som en linket server, kan du bruge resultatet af enhver forespørgsel (inklusive et lagret procedurekald) som en almindelig SELECT
. Så du kan gøre dette (bemærk, at databasepræfikset er vigtigt, ellers får du fejl 11529 og 2812):
SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Hvis vi kan udføre en SELECT *
, kan vi også udføre en SELECT * INTO
:
SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Og når først den #tmp-tabel eksisterer, kan vi bestemme metadataene ved at sige (forudsat SQL Server 2005 eller nyere):
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');
(Hvis du bruger SQL Server 2000, kan du gøre noget lignende med syskolonner, men jeg har ikke en 2000-instans til rådighed til at validere en tilsvarende forespørgsel.)
Resultater:
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
I Denali vil dette være meget, meget, meget nemmere. Igen er der stadig en begrænsning af det første resultatsæt, men du behøver ikke at konfigurere en forbundet server og springe gennem alle disse hoops. Du kan bare sige:
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);
Resultater:
name system_type_name
--------- ----------------
foo int
bar varchar(5)
Indtil Denali foreslår jeg, at det ville være nemmere bare at smøge ærmerne op og finde ud af datatyperne på egen hånd. Ikke kun fordi det er kedeligt at gennemgå ovenstående trin, men også fordi du er langt mere tilbøjelig til at foretage et korrekt (eller i det mindste mere præcist) gæt, end motoren vil, da datatypen, som gætter på, motoren laver, vil være baseret på driftstid output uden ekstern viden om domænet af mulige værdier. Denne faktor vil også forblive sand i Denali, så du skal ikke få indtrykket af, at de nye metadata-opdagelsesfunktioner er en endegyldig ende, de gør bare ovenstående lidt mindre kedeligt.
Og for nogle andre potentielle gotchas med OPENQUERY
, se Erland Sommarskogs artikel her:
http://www.sommarskog.se/share_data.html#OPENQUERY