sql >> Database teknologi >  >> RDS >> Sqlserver

Vil du hente kolonnenavne og typer af en lagret procedure?

[Jeg indså lige, at jeg har besvaret dette spørgsmål før]

At gøre dette for en lagret procedure er meget mere kompliceret, end det er for en visning eller tabel. Et af problemerne er, at en lagret procedure kan have flere forskellige kodestier afhængigt af inputparametre og endda ting, du ikke kan kontrollere som servertilstand, tidspunkt på dagen osv. Så for eksempel, hvad du ville forvente at se som output for denne lagrede procedure? Hvad hvis der er flere resultatsæt uanset betingelser?

CREATE PROCEDURE dbo.foo
  @bar INT
AS
BEGIN
  SET NOCOUNT ON;

  IF @bar = 1
    SELECT a, b, c FROM dbo.blat;
  ELSE
    SELECT d, e, f, g, h FROM dbo.splunge;
END
GO

Hvis din lagrede procedure ikke har kodestier, og du er sikker på, at du altid vil se det samme resultatsæt (og på forhånd kan bestemme, hvilke værdier der skal angives, hvis en lagret procedure har ikke-valgfrie parametre), lad os tage et simpelt eksempel:

CREATE PROCEDURE dbo.bar
AS
BEGIN
  SET NOCOUNT ON;

  SELECT a = 'a', b = 1, c = GETDATE();
END
GO

KUN FM

En måde er at gøre sådan noget:

SET FMTONLY ON;
GO
EXEC dbo.bar;

Dette vil give dig et tomt resultatsæt, og din klientapplikation kan tage et kig på egenskaberne for det resultatsæt for at bestemme kolonnenavne og datatyper.

Nu er der en masse problemer med SET FMTONLY ON; det vil jeg ikke komme ind på her, men det skal i det mindste bemærkes, at denne kommando er forældet - med god grund. Vær også omhyggelig med at SET FMTONLY OFF; når du er færdig, eller du vil undre dig over, hvorfor du opretter en lagret procedure med succes, men så ikke kan udføre den. Og nej, jeg advarer dig ikke om det, for det er lige sket for mig. Ærlig. :-)

OPENQUERY

Ved at oprette en loopback-linket server kan du derefter bruge værktøjer som OPENQUERY at udføre en lagret procedure, men returnere et sammensat resultatsæt (godkend venligst det som en ekstremt løs definition), som du kan inspicere. Opret først en loopback-server (dette forudsætter en lokal instans ved navn FOO ):

USE master;
GO
EXEC sp_addlinkedserver @server = N'.\FOO', @srvproduct=N'SQL Server'
GO
EXEC sp_serveroption @server=N'.\FOO', @optname=N'data access', 
  @optvalue=N'true';

Nu kan vi tage ovenstående procedure og indlæse den i en forespørgsel som denne:

SELECT * INTO #t 
FROM OPENQUERY([.\FOO], 'EXEC dbname.dbo.bar;')
WHERE 1 = 0;

SELECT c.name, t.name
FROM tempdb.sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
WHERE c.[object_id] = OBJECT_ID('tempdb..#t');

Dette ignorerer aliastyper (tidligere kendt som brugerdefinerede datatyper) og kan også vise to rækker for kolonner defineret som f.eks. sysname . Men fra ovenstående producerer den:

name   name
----   --------
b      int
c      datetime
a      varchar

Der er åbenbart mere arbejde at gøre her - varchar viser ikke længde, og du bliver nødt til at få præcision/skala for andre typer såsom datetime2 , time og decimal . Men det er en begyndelse.

SQL Server 2012

Der er nogle nye funktioner i SQL Server 2012, der gør opdagelse af metadata meget nemmere. Til ovenstående procedure kan vi gøre følgende:

SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
  OBJECT_ID('dbo.bar'), 
  NULL
);

Dette giver blandt andet faktisk præcision og skala og løser aliastyper for os. For ovenstående procedure giver dette:

name   system_type_name
----   ----------------
a      varchar(1)
b      int
c      datetime

Ikke meget forskel visuelt, men når du begynder at komme ind i alle de forskellige datatyper med forskellig præcision og skala, vil du sætte pris på det ekstra arbejde, denne funktion gør for dig.

Ulempen:I SQL Server 2012 virker i det mindste disse funktioner kun for den første resultset (som navnet på funktionen antyder).



  1. GIS:PostGIS/PostgreSQL vs. MySql vs. SQL Server?

  2. DATEDIFF_BIG() Eksempler i SQL Server

  3. Sådan registrerer du, om en værdi indeholder mindst ét ​​tal i SQL Server

  4. Sådan rettes FEJL:kolonne c.relhasoids findes ikke i Postgres?