Então, digamos que você tenha um procedimento armazenado em tempdb:
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Existe uma maneira bastante complicada de determinar os metadados que o procedimento armazenado produzirá. Existem várias ressalvas, incluindo o procedimento que só pode gerar um único conjunto de resultados e que uma melhor suposição será feita sobre o tipo de dados se não puder ser determinado com precisão. Requer o uso de
OPENQUERY
e um servidor vinculado de loopback com o 'DATA ACCESS'
propriedade definida como verdadeira. Você pode verificar sys.servers para ver se já tem um servidor válido, mas vamos apenas criar um manualmente chamado loopback
:EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Agora que você pode consultar isso como um servidor vinculado, você pode usar o resultado de qualquer consulta (incluindo uma chamada de procedimento armazenado) como um
SELECT
normal . Então você pode fazer isso (observe que o prefixo do banco de dados é importante, caso contrário, você receberá o erro 11529 e 2812):SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Se pudermos realizar um
SELECT *
, também podemos executar um SELECT * INTO
:SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
E uma vez que a tabela #tmp exista, podemos determinar os metadados dizendo (assumindo o SQL Server 2005 ou 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');
(Se você estiver usando o SQL Server 2000, poderá fazer algo semelhante com syscolumns, mas não tenho uma instância 2000 à mão para validar uma consulta equivalente.)
Resultados:
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
No Denali, isso será muito, muito, muito mais fácil. Novamente, ainda há uma limitação do primeiro conjunto de resultados, mas você não precisa configurar um servidor vinculado e passar por todos esses aros. Você pode apenas dizer:
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)
Até o Denali, sugiro que seria mais fácil apenas arregaçar as mangas e descobrir os tipos de dados por conta própria. Não apenas porque é tedioso seguir as etapas acima, mas também porque é muito mais provável que você faça uma estimativa correta (ou pelo menos mais precisa) do que o mecanismo, já que o tipo de dados que o mecanismo faz será baseado no tempo de execução saída, sem qualquer conhecimento externo do domínio de valores possíveis. Esse fator também permanecerá verdadeiro no Denali, portanto, não fique com a impressão de que os novos recursos de descoberta de metadados são tudo, eles apenas tornam o acima um pouco menos tedioso.
Ah, e para algumas outras pegadinhas em potencial com
OPENQUERY
, veja o artigo de Erland Sommarskog aqui:http://www.sommarskog.se/share_data.html#OPENQUERY