Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Récupérer la définition de colonne pour le jeu de résultats de la procédure stockée

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