sql >> Base de Datos >  >> RDS >> Sqlserver

Recuperar la definición de columna para el conjunto de resultados del procedimiento almacenado

Entonces, digamos que tiene un procedimiento almacenado en tempdb:

USE tempdb;
GO

CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
    SET NOCOUNT ON;

    SELECT foo = 1, bar = 'tooth';
END
GO

Hay una forma bastante complicada de determinar los metadatos que generará el procedimiento almacenado. Hay varias advertencias, incluido el procedimiento que solo puede generar un único conjunto de resultados, y que se hará una mejor suposición sobre el tipo de datos si no se puede determinar con precisión. Requiere el uso de OPENQUERY y un servidor enlazado loopback con el 'DATA ACCESS' propiedad establecida en verdadero. Puede verificar sys.servers para ver si ya tiene un servidor válido, pero creemos uno manualmente llamado loopback :

EXEC master..sp_addlinkedserver 
    @server = 'loopback',  
    @srvproduct = '',
    @provider = 'SQLNCLI',
    @datasrc = @@SERVERNAME;

EXEC master..sp_serveroption 
    @server = 'loopback', 
    @optname = 'DATA ACCESS',
    @optvalue = 'TRUE';

Ahora que puede consultar esto como un servidor vinculado, puede usar el resultado de cualquier consulta (incluida una llamada a un procedimiento almacenado) como SELECT normal. . Entonces puede hacer esto (tenga en cuenta que el prefijo de la base de datos es importante, de lo contrario obtendrá el error 11529 y 2812):

SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');

Si podemos realizar un SELECT * , también podemos realizar un SELECT * INTO :

SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');

Y una vez que existe la tabla #tmp, podemos determinar los metadatos diciendo (suponiendo que SQL Server 2005 o superior):

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 usa SQL Server 2000, puede hacer algo similar con syscolumns, pero no tengo una instancia de 2000 a mano para validar una consulta equivalente).

Resultados:

name      type    max_length precision scale
--------- ------- ---------- --------- -----
foo       int              4        10     0
bar       varchar          5         0     0

En Denali, esto será mucho, mucho, mucho más fácil. Nuevamente, todavía hay una limitación del primer conjunto de resultados, pero no tiene que configurar un servidor vinculado y pasar por todos esos aros. Solo puedes decir:

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);

Resultados:

name      system_type_name
--------- ----------------
foo       int             
bar       varchar(5)      

Hasta Denali, sugiero que sería más fácil arremangarse y descubrir los tipos de datos por su cuenta. No solo porque es tedioso realizar los pasos anteriores, sino también porque es mucho más probable que haga una conjetura correcta (o al menos más precisa) que el motor, ya que el tipo de datos conjetura que hace el motor se basará en el tiempo de ejecución. salida, sin ningún conocimiento externo del dominio de valores posibles. Este factor seguirá siendo cierto en Denali también, así que no tenga la impresión de que las nuevas funciones de descubrimiento de metadatos son el final de todo, simplemente hacen que lo anterior sea un poco menos tedioso.

Ah, y para algunas otras trampas potenciales con OPENQUERY , consulte el artículo de Erland Sommarskog aquí:

http://www.sommarskog.se/share_data.html#OPENQUERY