sql >> Database >  >> RDS >> Sqlserver

Kolomdefinitie ophalen voor resultaatset opgeslagen procedure

Dus laten we zeggen dat je een opgeslagen procedure hebt in tempdb:

USE tempdb;
GO

CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
    SET NOCOUNT ON;

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

Er is een nogal ingewikkelde manier om de metadata te bepalen die de opgeslagen procedure zal uitvoeren. Er zijn verschillende kanttekeningen, waaronder dat de procedure slechts één resultaatset kan opleveren, en dat er een beste schatting zal worden gemaakt over het gegevenstype als het niet precies kan worden bepaald. Het vereist het gebruik van OPENQUERY en een loopback-gekoppelde server met de 'DATA ACCESS' eigenschap ingesteld op true. Je kunt sys.servers controleren om te zien of je al een geldige server hebt, maar laten we er gewoon een handmatig maken met de naam loopback :

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

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

Nu u dit als gekoppelde server kunt opvragen, kunt u het resultaat van elke zoekopdracht (inclusief een opgeslagen procedureaanroep) gebruiken als een gewone SELECT . U kunt dit dus doen (merk op dat het databasevoorvoegsel is belangrijk, anders krijg je fout 11529 en 2812):

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

Als we een SELECT * . kunnen uitvoeren , we kunnen ook een SELECT * INTO . uitvoeren :

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

En zodra die #tmp-tabel bestaat, kunnen we de metadata bepalen door te zeggen (ervan uitgaande dat SQL Server 2005 of hoger):

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

(Als u SQL Server 2000 gebruikt, kunt u iets soortgelijks doen met syscolumns, maar ik heb geen 2000-instantie bij de hand om een ​​gelijkwaardige query te valideren.)

Resultaten:

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

In Denali zal dit veel, veel, veel gemakkelijker zijn. Nogmaals, er is nog steeds een beperking van de eerste resultatenset, maar je hoeft geen gekoppelde server op te zetten en door al die hoepels te springen. Je kunt gewoon zeggen:

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

Resultaten:

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

Tot Denali stel ik voor dat het gemakkelijker zou zijn om gewoon je mouwen op te stropen en zelf de gegevenstypen te achterhalen. Niet alleen omdat het vervelend is om de bovenstaande stappen te doorlopen, maar ook omdat het veel waarschijnlijker is dat u een juiste (of op zijn minst nauwkeurigere) schatting maakt dan de engine zal doen, aangezien het gegevenstype dat de engine vermoedt gebaseerd is op runtime output, zonder enige externe kennis van het domein van mogelijke waarden. Deze factor blijft ook gelden in Denali, dus krijg niet de indruk dat de nieuwe functies voor het ontdekken van metadata alles zijn, ze maken het bovenstaande alleen wat minder vervelend.

Oh en voor een aantal andere mogelijke problemen met OPENQUERY , zie hier het artikel van Erland Sommarskog:

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



  1. Hoe MySQL-databases in de opdrachtregel te importeren

  2. MySQL #1140 - Mengen van GROEP-kolommen

  3. Door komma's gescheiden kolomgegevens in extra kolommen splitsen

  4. DATEFROMPARTS() Voorbeelden in SQL Server (T-SQL)