Wie werden die Eingabe- und Ausgabewerte von gespeicherten Prozeduren ermittelt?

7

Ich habe Hunderte von SPs und möchte herausfinden:

  • Eingabeparameter mit Typ
  • Ausgabefelder mit Typ (keine Ausgabeparameter)

Natürlich könnte ich jedes manuell durchgehen und es aufschreiben, aber wo ist der Spaß daran ... Nein, buchstäblich, wo ist der Spaß daran :)

Kann dies durchgeführt werden oder verfügt SQL Management Studio 2008 R2 bereits über diese Funktion?

Ich weiß nicht einmal, wo ich anfangen soll, daher ist jede Antwort akzeptabel.

Bearbeiten zur Verbesserung der Frage: Wenn wir es als zwei verschiedene Aufgaben betrachten, könnten wir dies einfacher erreichen. Auch mit Reflexion auf der Client-Seite. (Eine schnelle und schmutzige Konsolen-App würde ausreichen.)

Michael Wells
quelle
1
Was meinst du mit "Ausgabefeldern"? Sprechen Sie über Ausgabeparameter oder die Spalten in den Ergebnismengen?
Martin Smith
Was ist der Unterschied? Kann ich auch beide gleichzeitig haben? Alles, was mich wirklich interessiert, ist, welche Art von Daten ich zurückbekomme. Ich bin neu in der Terminologie. Ich dachte, Spalten werden auch als Felder bezeichnet. Aber wie Marian feststellt, meinte ich "Spalten in der Ergebnismenge". :)
Michael Wells
1
Spalten und Felder sind auch ziemlich. Grund für die Frage war, dass Sie die Eingabeparameter explizit erwähnt haben und daher nicht sicher waren, ob Sie dort auf Ausgabeparameter verweisen wollten. Derzeit gibt es keine gute Möglichkeit, die Spaltenliste abzurufen (und es kann mehr als eine Ergebnismenge geben oder ihre Form kann je nach Verfahrenscode im Prozess variieren). Visual Studio führt SET FMTONLY ON;die gespeicherte Prozedur aus und führt sie aus . SQL Server 2012 verfügt über einige zusätzliche Funktionen, die hier hilfreich sind.
Martin Smith
Was sind Ausgabeparameter?
Michael Wells
1
Parameter, die mit dem outputSchlüsselwort verziert sind, das im proc zugewiesen werden kann, und dem Wert, der vom Aufrufer der gespeicherten Prozedur abgerufen wird. Nützlich, wenn Sie Skalarwerte anstelle von Datenzeilen zurückgeben möchten. Sie sind tatsächlich Eingabe- / Ausgabeparameter, da sie auch zum Übergeben von Werten an die Prozedur verwendet werden können.
Martin Smith

Antworten:

4

Sie sollten dies in der Systemansicht INFORMATION_SCHEMA.PARAMETERS tun können . Sie haben dort, was Sie brauchen.

"Es wird eine Zeile für jeden Parameter einer benutzerdefinierten Funktion oder gespeicherten Prozedur zurückgegeben, auf die der aktuelle Benutzer in der aktuellen Datenbank zugreifen kann. Für Funktionen gibt diese Ansicht auch eine Zeile mit Rückgabewertinformationen zurück."

PS: Wenn die Antwort auf Martins Frage "Spalten in der Ergebnismenge" lautet, ignorieren Sie meine Antwort. Dies gilt nur für die Parameter der Prozeduren, nicht für ein Ergebnis.

Marian
quelle
3

Für Ein- und Ausgangsparameter können Sie sehen sys.parameters, sys.proceduresund sys.types. Hier ist eine Prozedur mit verschiedenen Eingabe- / Ausgabeparametern, Alias-Typen und sogar einem TVP (nur 2008+):

USE [tempdb];
GO

CREATE TYPE dbo.TVPType AS TABLE(id INT);
GO

CREATE PROCEDURE dbo.foobar
    @a INT,
    @b SYSNAME = N'foo',
    @c DATETIME = NULL,
    @d dbo.TVPType READONLY,
    @e NVARCHAR(MAX),
    @f INT OUTPUT,
    @g INT = NULL OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT @f = COUNT(*) FROM sys.objects;
END
GO

Und hier ist eine Abfrage, um diese Informationen abzurufen sys.parameters, sys.proceduresund sys.types:

SELECT 
    s = QUOTENAME(OBJECT_SCHEMA_NAME(p.[object_id])),
    o = QUOTENAME(p.name),
    p = pr.name, 
    t1.name,
    pr.max_length, 
    pr.[precision], 
    pr.scale, 
    pr.is_output,
    pr.is_readonly
FROM sys.procedures AS p
INNER JOIN sys.parameters AS pr
ON p.[object_id] = pr.[object_id]
LEFT OUTER JOIN sys.types AS t1 
ON (pr.system_type_id = t1.system_type_id)
AND (pr.system_type_id <> t1.system_type_id
OR pr.user_type_id = t1.user_type_id)
WHERE p.[object_id] = OBJECT_ID('dbo.foobar')
ORDER BY pr.parameter_id;

Ergebnisse:

s       o           p   name    max_length  [precision]  scale  is_output  is_readonly
-----   ----------  --- -------- ---------  -----------  -----  ---------  -----------
[dbo]   [foobar]    @a  int              4           10      0          0            0
[dbo]   [foobar]    @b  sysname        256            0      0          0            0
[dbo]   [foobar]    @c  datetime         8           23      3          0            0
[dbo]   [foobar]    @d  TVPType         -1            0      0          0            1
[dbo]   [foobar]    @e  nvarchar        -1            0      0          0            0
[dbo]   [foobar]    @f  int              4           10      0          1            0
[dbo]   [foobar]    @g  int              4           10      0          1            0

Offensichtlich müssen Sie einige Massagen durchführen, damit diese Werte wie echte Datentypen aussehen. Schneiden Sie beispielsweise die max_length eines nvarchar in zwei Hälften, es sei denn, es ist -1. In diesem Fall muss es ausgetauscht werden MAX. Fügen Sie für Dezimalzahlen, Zahlen usw. die Genauigkeit und Skalierung entsprechend hinzu. Wenn Sie TVPs verwenden, möchten Sie wahrscheinlich das Schema SCHEMA_NAMEfür diese Typen abrufen. Usw. usw.

Leider gibt es keine andere Möglichkeit als Brute-Force-Analyse des Prozedurkörpers (und selbst das ist ohne ernsthafte Ninja-RegEx-Kenntnisse nicht trivial), um festzustellen, ob der Parameter nullwertfähig ist oder ob er einen Standardwert hat und wie der Standardwert lautet. Diese Informationen werden einfach nicht in den Metadaten gespeichert - während sie vorhanden sind has_default_valueund default_valueSpalten enthalten sys.parameters, sind sie NULLfür CLR-Prozeduren immer nur ungleich oder ungleich Null. Ich habe mich seit 2006 darüber beschwert, aber wir haben noch keine Fortschritte in diesem Bereich zu sehen (obwohl ich eine Problemumgehung für dieses Connect-Element veröffentlicht habe, die ich hier nicht reproduzieren werde, da einige unangemessene Annahmen über den Codierungsstil Ihrer gespeicherten Prozeduren getroffen werden). Und es gibt überhaupt nichts, was Hoffnung gibt, festzustellen, ob der Parameter optional ist (z . B. @cund @ghöher).

Bei den Ergebnismengen hat Martin völlig Recht - es gibt keine zuverlässige Methode, um herauszufinden, woraus ein Ergebnis bestehen wird, außer die Verwendung SET FMTONLY ON. Es gibt einige eigenartige Fehler bei diesem, also würde ich mich davon fernhalten. Eine beliebte Flickschusterei ist die Verwendung OPENQUERYmit einem „Loopback“ verknüpften Server , wählen Sie die Ergebnisse in eine #temp Tabelle, aber das funktioniert nur , wenn die Prozedur genau ein resultset hat. Ein gutes Beispiel findet sich in einer der vorherigen Antworten von Martin:

Was ist der einfachste Weg, um eine temporäre Tabelle in SQL Server zu erstellen, die das Ergebnis einer gespeicherten Prozedur enthalten kann?

Sobald Sie die Ausgabe in die Tabelle #temp eingefügt haben, können Sie Folgendes ausführen:

EXEC tempdb..sp_help '#tablename';

Dies gibt unter anderem eine Liste von Spaltennamen und deren Datentypen aus. Während dies für Hunderte von gespeicherten Prozeduren ein langwieriger Prozess sein wird, habe ich Ideen zur Automatisierung. Wenn dies für Sie eine interessante Lösung ist, lassen Sie es mich bitte wissen und ich kann meine Antwort erweitern.

Martin auch neue Funktionen in SQL Server 2012 angedeutet , dass dies ein machen wird viel einfacher (aber es ist immer noch auf den ersten resultset einer gespeicherten Prozedur begrenzt). Weitere Details dazu finden Sie in meiner Antwort auf dieselbe Frage oben.

Für Rückgabewerte kenne ich keine Möglichkeit, diese aus den Metadaten abzurufen.

Aaron Bertrand
quelle
Danke, dass Sie Dinge geschrieben und erklärt haben. Wenn Sie nicht wissen, was Ergebnis-Sests sind, handelt es sich um einen Datensatz mit mehreren Datentabellen?
Michael Wells
Die Ergebnismenge von der SELECTAbfrage oben? Haben Sie es ausgeführt (nur den Namen der zu suchenden Prozedur geändert)? Es handelt sich um eine einzelne Ergebnismenge, die eine Zeile für pro Parameter enthält (sie wird nur dann zu einer "Datentabelle", wenn Sie sie in .NET verwenden und so gestalten).
Aaron Bertrand
Alles, was ich wirklich brauche, ist eine schnelle Möglichkeit, unsere SPs zunächst zu dokumentieren und festzustellen, ob doppelte Datensätze / Skalare zurückgegeben werden. Ich glaube nicht, dass wir nur wenige haben, die mehrere Datentabellen in einem Datensatz zurückgeben. Ich habe die Eingabeparameter bereits in unsere SPs und Funktionen in eine Excel-Tabelle exportiert, aber die resultierenden Datensätze noch nicht erhalten. Ich mag die Idee der Automatisierung, die Sie erwähnt haben, und ich habe kein Problem damit, Daten zu massieren. Ich dachte darüber nach, ein Programm zu schreiben, um die Liste der SP und Funktionen zu erhalten, und jedes an eine Abfrage zu übergeben, um eine Liste der Eingabeparameter zu generieren und zu verwenden
Michael Wells
Reflexion über das resultierende Dataset, um die Spaltennamen und Datentypen abzurufen. Ich denke, ich könnte einfach Ihre SQL-Abfrage ausprobieren, um die Ausgabe zu generieren, und sie dann in einem zweiten Durchgang massieren.
Michael Wells
Ah, ich verstehe jetzt. Entschuldigung, aber wie ich vorgeschlagen habe, gibt es wirklich keine Möglichkeit, Duplikate in den Ergebnismengen zu erkennen, ohne den Bereich der Eingabewerte für die Prozeduren zu kennen und sie auszuführen.
Aaron Bertrand