Supposons que vous ayez une procédure stockée dans tempdb :
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Il existe une manière assez compliquée de déterminer les métadonnées que la procédure stockée produira. Il y a plusieurs mises en garde, y compris la procédure ne peut produire qu'un seul ensemble de résultats, et qu'une meilleure estimation sera faite sur le type de données s'il ne peut pas être déterminé avec précision. Il nécessite l'utilisation de OPENQUERY
et un serveur lié en boucle avec le 'DATA ACCESS'
propriété définie sur true. Vous pouvez vérifier sys.servers pour voir si vous avez déjà un serveur valide, mais créons-en un manuellement appelé loopback
:
EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Maintenant que vous pouvez interroger ceci en tant que serveur lié, vous pouvez utiliser le résultat de n'importe quelle requête (y compris un appel de procédure stockée) comme un SELECT
normal . Vous pouvez donc le faire (notez que le préfixe de la base de données est important, sinon vous obtiendrez les erreurs 11529 et 2812) :
SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Si nous pouvons effectuer un SELECT *
, nous pouvons également effectuer un SELECT * INTO
:
SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Et une fois que cette table #tmp existe, nous pouvons déterminer les métadonnées en disant (en supposant que SQL Server 2005 ou supérieur) :
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');
(Si vous utilisez SQL Server 2000, vous pouvez faire quelque chose de similaire avec syscolumns, mais je n'ai pas d'instance 2000 à portée de main pour valider une requête équivalente.)
Résultats :
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
À Denali, ce sera beaucoup, beaucoup, beaucoup plus facile. Encore une fois, il y a toujours une limitation du premier ensemble de résultats, mais vous n'avez pas besoin de configurer un serveur lié et de sauter à travers tous ces cerceaux. Vous pouvez simplement dire :
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);
Résultats :
name system_type_name
--------- ----------------
foo int
bar varchar(5)
Jusqu'à Denali, je suggère qu'il serait plus facile de simplement retrousser vos manches et de déterminer vous-même les types de données. Non seulement parce qu'il est fastidieux de suivre les étapes ci-dessus, mais aussi parce que vous êtes beaucoup plus susceptible de faire une estimation correcte (ou du moins plus précise) que le moteur, puisque le type de données que le moteur devine sera basé sur le temps d'exécution sortie, sans aucune connaissance externe du domaine des valeurs possibles. Ce facteur restera également vrai dans Denali, alors n'ayez pas l'impression que les nouvelles fonctionnalités de découverte de métadonnées sont une fin en soi, elles rendent simplement ce qui précède un peu moins fastidieux.
Oh et pour d'autres pièges potentiels avec OPENQUERY
, voir l'article d'Erland Sommarskog ici :
http://www.sommarskog.se/share_data.html#OPENQUERY