[Mir ist gerade aufgefallen, dass ich diese Frage schon einmal beantwortet habe]
Dies ist für eine gespeicherte Prozedur viel komplizierter als für eine Ansicht oder Tabelle. Eines der Probleme besteht darin, dass eine gespeicherte Prozedur je nach Eingabeparametern und sogar Dingen, die Sie nicht steuern können, wie Serverstatus, Tageszeit usw., mehrere unterschiedliche Codepfade haben kann. Also zum Beispiel, was Sie als Ausgabe erwarten würden diese gespeicherte Prozedur? Was ist, wenn es unabhängig von Bedingungen mehrere Ergebnismengen gibt?
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
Wenn Ihre gespeicherte Prozedur keine Codepfade hat und Sie sicher sind, dass Sie immer die gleiche Ergebnismenge sehen (und im Voraus bestimmen können, welche Werte geliefert werden sollen, wenn eine gespeicherte Prozedur nicht optionale Parameter hat), nehmen wir ein einfaches Beispiel:
CREATE PROCEDURE dbo.bar
AS
BEGIN
SET NOCOUNT ON;
SELECT a = 'a', b = 1, c = GETDATE();
END
GO
FMTONLY
Eine Möglichkeit ist, so etwas zu tun:
SET FMTONLY ON;
GO
EXEC dbo.bar;
Dadurch erhalten Sie eine leere Ergebnismenge und Ihre Clientanwendung kann sich die Eigenschaften dieser Ergebnismenge ansehen, um Spaltennamen und Datentypen zu bestimmen.
Jetzt gibt es viele Probleme mit SET FMTONLY ON;
auf die ich hier nicht weiter eingehen werde, aber zumindest sollte angemerkt werden, dass dieser Befehl veraltet ist - aus gutem Grund. Achten Sie auch auf SET FMTONLY OFF;
wenn Sie fertig sind, oder Sie fragen sich, warum Sie eine gespeicherte Prozedur erfolgreich erstellen, sie dann aber nicht ausführen können. Und nein, ich warne Sie nicht davor, weil es mir gerade passiert ist. Ehrlich. :-)
OPENQUERY
Indem Sie einen Loopback-Verbindungsserver erstellen, können Sie dann Tools wie OPENQUERY
verwenden um eine gespeicherte Prozedur auszuführen, aber eine zusammensetzbare Ergebnismenge zurückzugeben (na ja, bitte akzeptieren Sie das als eine extrem lockere Definition), die Sie überprüfen können. Erstellen Sie zuerst einen Loopback-Server (dies setzt eine lokale Instanz namens FOO
voraus ):
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';
Jetzt können wir das obige Verfahren nehmen und es in eine Abfrage wie diese einfügen:
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');
Dies ignoriert Aliastypen (früher bekannt als benutzerdefinierte Datentypen) und zeigt möglicherweise auch zwei Zeilen für Spalten an, die beispielsweise als sysname
definiert sind . Aber aus dem obigen ergibt es:
name name
---- --------
b int
c datetime
a varchar
Offensichtlich gibt es hier noch mehr zu tun - varchar
zeigt keine Länge an, und Sie müssen Genauigkeit/Skalierung für andere Typen wie datetime2
erhalten , time
und decimal
. Aber das ist ein Anfang.
SQL-Server 2012
Es gibt einige neue Funktionen in SQL Server 2012, die die Erkennung von Metadaten erheblich vereinfachen. Für das obige Verfahren können wir Folgendes tun:
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
OBJECT_ID('dbo.bar'),
NULL
);
Dies liefert unter anderem tatsächlich Präzision und Skalierung und löst Aliastypen für uns auf. Für das obige Verfahren ergibt dies:
name system_type_name
---- ----------------
a varchar(1)
b int
c datetime
Optisch kein großer Unterschied, aber wenn Sie anfangen, mit unterschiedlicher Genauigkeit und Skalierung in all die verschiedenen Datentypen einzusteigen, werden Sie die zusätzliche Arbeit zu schätzen wissen, die diese Funktion für Sie erledigt.
Die Kehrseite:Zumindest in SQL Server 2012 funktionieren diese Funktionen nur für den ersten Ergebnismenge (wie der Name der Funktion schon sagt).