SQL Server - SELECT FROM gespeicherte Prozedur

333

Ich habe eine gespeicherte Prozedur, die Zeilen zurückgibt:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Mein eigentliches Verfahren ist etwas komplizierter, weshalb ein Sproc notwendig ist.

Ist es möglich, die Ausgabe durch Aufrufen dieser Prozedur auszuwählen?

Etwas wie:

SELECT * FROM (EXEC MyProc) AS TEMP

Ich brauche zu verwenden SELECT TOP X, ROW_NUMBERund eine zusätzliche WHEREKlausel meine Daten zu Seite, und ich will nicht wirklich diese Werte als Parameter übergeben.

Jonathanpeppers
quelle
Ich bin mir nicht sicher, was Sie hier vorhaben, denn wenn Sie die Prozedur ausführen, erhalten Sie die Zeilen zurück. Möchten Sie die Prozedur in einer SELECT-Anweisung ausführen, damit Sie sie an ein pageable Objekt binden können?
Raj More
1
Gibt es einen bestimmten Grund, warum Sie die Werte nicht als Parameter übergeben möchten? Es ist ein bisschen ineffizient, es so zu machen, wie Sie es vorschlagen - Sie würden mehr Daten auswählen, als Sie benötigen, und dann nicht alles verwenden.
Mark Bell
2
Werfen
Pylover

Antworten:

149

Sie können anstelle einer Prozedur eine benutzerdefinierte Funktion oder eine Ansicht verwenden.

Eine Prozedur kann mehrere Ergebnismengen mit jeweils einem eigenen Schema zurückgeben. Es ist nicht für die Verwendung in einer SELECTAnweisung geeignet .

Mehrdad Afshari
quelle
8
Wenn Sie nach der Konvertierung in eine UDF die Semantik der gespeicherten Prozedur benötigen, können Sie die UDF jederzeit mit einer Prozedur umschließen.
Joel Coehoorn
Was ist, wenn wir Parameter an mehrere gespeicherte Prozeduren senden und diese zu einer großen gespeicherten Prozedur kombinieren müssen? Kann Parameter anzeigen, übernehmen, wie es gespeicherte Prozeduren
tun
3
@mrN-Ansichten akzeptieren keine Parameter, UDFs jedoch.
Mehrdad Afshari
3
Hallo, ich muss das wirklich tun, ohne das SP in eine Ansicht oder Funktion zu konvertieren. Ist das möglich?
Luis Becerril
2
Während Ihre Antwort eine wahre Aussage ist, beantwortet sie die Frage nicht ... "AUS gespeicherter Prozedur AUSWÄHLEN" Was sicher nicht ideal ist, aber es ist, was es ist ... @ Aamirs Antwort ist die richtige Antwort. Entweder das oder die Frage muss geändert werden ... was mir ein bisschen lächerlich erscheint.
Urasquirrel
201

Du kannst

  1. Erstellen Sie eine Tabellenvariable, um die Ergebnismenge aus dem gespeicherten Prozess zu speichern, und dann
  2. Fügen Sie die Ausgabe des gespeicherten Prozesses in die Tabellenvariable ein und dann
  3. Verwenden Sie die Tabellenvariable genau wie jede andere Tabelle ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...
Charles Bretana
quelle
34
Das Problem mit INSERT #Toder INSERT @Tist, dass eine INSERT EXECAnweisung nicht verschachtelt werden kann. Wenn die gespeicherte Prozedur bereits eine enthält INSERT EXEC, funktioniert dies nicht.
MOHCTP
2
Dies ist wahrscheinlich die portabelste Lösung, die dem grundlegenden SQL am nächsten kommt. Es ist auch hilfreich, starke Definitionen für Spaltentypen beizubehalten. Sollte mehr positive Stimmen haben als die oben genannten.
Die Tabellenvariablen sehen hier in Bezug auf die sp-Kompilierung nützlicher aus als temporäre Tabellen. Daher stimme ich zu, dass diese Antwort mehr positive Stimmen haben sollte.
resnyanskiy
76

Sie möchten entweder eine Tabellenwertfunktion oder fügen Ihre EXEC in eine temporäre Tabelle ein:

INSERT INTO #tab EXEC MyProc
CMerat
quelle
31
Das Problem mit INSERT #Toder INSERT @Tist, dass eine INSERT EXECAnweisung nicht verschachtelt werden kann. Wenn die gespeicherte Prozedur bereits eine enthält INSERT EXEC, funktioniert dies nicht.
MOHCTP
46

Sie müssen über OPENROWSET und OPENQUERY lesen

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
Rizwan Mumtaz
quelle
4
Wie bekomme ich YOURSERVERNAME dynamisch? Sie können nicht erwarten, immer wissen zu müssen. Wird diese Pause nicht jeden zweiten Dienstag stattfinden? Also, wenn ich 100 Server habe, alle mit unterschiedlichen Namen ...
Urasquirrel
Was ist auch, wenn meine Datenbank nicht dafür konfiguriert ist?
Urasquirrel
4
Versuchen Sie @@ Servername, um es dynamisch zu bekommen
Siddhartha Gandhi
44

Sie müssen einen Tabellentyp deklarieren, der die gleiche Anzahl von Spalten enthält, die Ihre Speicherprozedur zurückgibt. Die Datentypen der Spalten im Tabellentyp und der von den Prozeduren zurückgegebenen Spalten sollten identisch sein

declare @MyTableType as table
(
FIRSTCOLUMN int
,.....
)  

Dann müssen Sie das Ergebnis Ihrer gespeicherten Prozedur in Ihren soeben definierten Tabellentyp einfügen

Insert into @MyTableType 
EXEC [dbo].[MyStoredProcedure]

Am Ende wählen Sie einfach aus Ihrem Tabellentyp

Select * from @MyTableType
Aamir
quelle
Das ist die beste Lösung für mich, da Sie weder den Servernamen noch die Verbindungszeichenfolgen angeben oder Verbindungsserver konfigurieren müssen, damit dies funktioniert. Dies sind Dinge, die ich nicht tun möchte, um sie nur zu erhalten einige Daten zurück. Vielen Dank! Ehrfürchtige Antwort!
Matt
Schöne Antwort Nah ೋ ღ❤ღ ೋ❤ ღ
Nahid
Wenn die gespeicherte Prozedur zu schwierig ist - diese Methode funktioniert beispielsweise nicht, wenn die gespeicherte Prozedur zwei temporäre Tabellen verwendet.
nick_n_a
34

Es ist nicht erforderlich, eine temporäre Tabelle zu verwenden.

Das ist meine Lösung

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue
DavideDM
quelle
2
Dazu müssen Sie Ihren Server als Verbindungsserver zu sich selbst hinzufügen, aber es funktioniert wie ein Zauber! Vielen Dank!
Vaheeds
Einige große Vorbehalte dazu: stackoverflow.com/questions/2374741/…
Keith Adler
1
Hmm ... Ich erhalte die Fehlermeldung "Fehler 7411: Server 'YourServerName' ist nicht für den Datenzugriff konfiguriert." Was muss ich ändern?
Matt
Haben Sie Ihren Server als Verbindungsserver hinzugefügt? YourServerName ist der Name Ihres Servers. Sie müssen Ihren Servernamen mit Ihrem tatsächlichen Servernamen ändern.
DavideDM
@ Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
Alexkovelsky
23

Sie können die Ausgabe von sp in die temporäre Tabelle kopieren.

CREATE TABLE #GetVersionValues
(
    [Index] int,
    [Name]  sysname,
    Internal_value  int,
    Character_Value sysname
)
INSERT #GetVersionValues EXEC master.dbo.xp_msver 'WindowsVersion'
SELECT * FROM #GetVersionValues
drop TABLE #GetVersionValues

quelle
7

benutze OPENQUERY und bevor du ausführst, setze 'SET FMTONLY OFF; SET NOCOUNT ON; '

Probieren Sie diesen Beispielcode aus:

SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE  [database].[dbo].[storedprocedure]  value,value ')
Ali asghar Fendereski
quelle
6

Konvertieren Sie Ihre Prozedur in eine Inline-Funktion, die eine Tabelle wie folgt zurückgibt:

CREATE FUNCTION MyProc()
RETURNS TABLE AS
RETURN (SELECT * FROM MyTable)

Und dann können Sie es als nennen

SELECT * FROM MyProc()

Sie haben auch die Möglichkeit, Parameter wie folgt an die Funktion zu übergeben:

CREATE FUNCTION FuncName (@para1 para1_type, @para2 para2_type , ... ) 

Und nenn es

SELECT * FROM FuncName ( @para1 , @para2 )
al_the_man
quelle
6

Wenn 'DATA ACCESS' false ist,

EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE

nach,

SELECT  *  FROM OPENQUERY(SQLSERVERNAME, 'EXEC DBNAME..MyProc @parameters')

Es klappt.

Ali Osman Yavuz
quelle
5

Mit OPENROWSET können Sie ein wenig schummeln:

SELECT ...fieldlist...
FROM OPENROWSET('SQLNCLI', 'connection string', 'name of sp')
WHERE ...

Dies würde natürlich immer noch den gesamten SP ausführen.

MartW
quelle
4

Der Einfachheit halber und um es wieder ausführbar zu machen, habe ich ein System StoredProcedure "sp_readerrorlog" verwendet, um Daten abzurufen:

-----USING Table Variable
DECLARE @tblVar TABLE (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(MAX),
   [Text] NVARCHAR(MAX)
)
INSERT INTO @tblVar Exec sp_readerrorlog
SELECT LogDate as DateOccured, ProcessInfo as pInfo, [Text] as Message FROM @tblVar



-----(OR): Using Temp Table
IF OBJECT_ID('tempdb..#temp') IS NOT NULL  DROP TABLE #temp;
CREATE TABLE #temp (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(55),
   Text NVARCHAR(MAX)
)
INSERT INTO #temp EXEC sp_readerrorlog
SELECT * FROM #temp
Scheich Kawser
quelle
1

Es hört sich so an, als müssten Sie möglicherweise nur eine Ansicht verwenden . In einer Ansicht kann eine Abfrage als Tabelle dargestellt werden, sodass die Ansicht abgefragt werden kann.

Lawrence Barsanti
quelle
1

Wenn Ihr Server zum Beispiel SERVERX heißt, habe ich das so gemacht ...

EXEC sp_serveroption 'SERVERX', 'DATA ACCESS', TRUE;
DECLARE @CMD VARCHAR(1000);
DECLARE @StudentID CHAR(10);
SET @StudentID = 'STUDENT01';
SET @CMD = 'SELECT * FROM OPENQUERY([SERVERX], ''SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE MYDATABASE.dbo.MYSTOREDPROC ' + @StudentID + ''') WHERE SOMEFIELD = SOMEVALUE';
EXEC (@CMD);

Um zu überprüfen, ob dies funktioniert, habe ich die EXEC()Befehlszeile auskommentiert und durch ersetztSELECT @CMD , um den Befehl zu überprüfen, bevor versuchte, ihn auszuführen! Damit sollte sichergestellt werden, dass alle richtigen Anführungszeichen am richtigen Ort sind. :-)

Ich hoffe das hilft jemandem.

Fandango68
quelle