SQL Server - SELECT FROM procédure stockée

334

J'ai une procédure stockée qui renvoie des lignes:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Ma procédure actuelle est un peu plus compliquée, c'est pourquoi un sproc est nécessaire.

Est-il possible de sélectionner la sortie en appelant cette procédure?

Quelque chose comme:

SELECT * FROM (EXEC MyProc) AS TEMP

J'ai besoin d'utiliser SELECT TOP X,, ROW_NUMBERet une WHEREclause supplémentaire pour paginer mes données, et je ne veux pas vraiment passer ces valeurs en tant que paramètres.

jonathanpeppers
la source
Je ne suis pas sûr de ce que vous avez l'intention de faire ici, car lorsque vous exécutez la procédure, vous récupérez les lignes. Est-ce que vous voulez exécuter la procédure à l'intérieur d'une instruction SELECT pour pouvoir la lier à un objet paginable?
Raj More
1
Y a-t-il une raison particulière pour laquelle vous ne voulez pas transmettre les valeurs en tant que paramètres? Pour le faire comme vous le suggérez est un peu inefficace - vous sélectionneriez plus de données que vous n'en avez besoin, puis vous ne les utiliseriez pas toutes.
Mark Bell
2
Jetez un oeil ici: sommarskog.se/share_data.html
pylover

Réponses:

149

Vous pouvez utiliser une fonction définie par l' utilisateur ou une vue au lieu d'une procédure.

Une procédure peut renvoyer plusieurs jeux de résultats, chacun avec son propre schéma. Il ne convient pas pour une utilisation dans une SELECTdéclaration.

Mehrdad Afshari
la source
8
De plus, si après la conversion en UDF vous trouvez que vous avez besoin de la sémantique de procédure stockée, vous pouvez toujours envelopper l'UDF avec une procédure.
Joel Coehoorn
que faire si, nous devons envoyer des paramètres à plusieurs procédures stockées et les combiner en une seule grande procédure stockée? Peut afficher, prendre des paramètres, comme le font les procédures stockées
mrN
3
@mrN Les vues ne prennent pas de paramètres, mais les UDF le font.
Mehrdad Afshari
3
Bonjour, j'ai vraiment besoin de faire cela sans convertir le sp en une vue ou une fonction, est-ce possible?
Luis Becerril
2
Bien que votre réponse soit une affirmation vraie, elle ne répond pas à la question .... "SÉLECTIONNEZ À PARTIR DE la procédure stockée" Ce qui, bien sûr, n'est pas idéal, mais c'est ce que c'est ... @ La réponse d'Aamir est la bonne réponse. Soit cela, soit la question doit être changée ... ce qui me semble un peu ridicule.
Urasquirrel
202

Vous pouvez

  1. créer une variable de table pour contenir le jeu de résultats à partir du proc stocké, puis
  2. insérez la sortie du proc stocké dans la variable de table, puis
  3. utilisez la variable de table exactement comme vous le feriez pour n'importe quelle autre table ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...
Charles Bretana
la source
34
Le problème avec INSERT #Tou INSERT @Test qu'une INSERT EXECinstruction ne peut pas être imbriquée. Si la procédure stockée contient déjà un INSERT EXEC, cela ne fonctionnera pas.
MOHCTP
2
C'est probablement la solution la plus portable, étant la plus proche du SQL de base. Il permet également de conserver des définitions de type de colonne solides. Devrait avoir plus de votes positifs que ceux ci-dessus.
Les variables de table semblent plus utiles ici que les tables temporaires en termes de recompilation sp. Je suis donc d'accord, cette réponse devrait avoir plus de votes positifs.
resnyanskiy
76

Vous voulez soit une fonction Table-Valued soit insérer votre EXEC dans une table temporaire:

INSERT INTO #tab EXEC MyProc
CMerat
la source
32
Le problème avec INSERT #Tou INSERT @Test qu'une INSERT EXECinstruction ne peut pas être imbriquée. Si la procédure stockée contient déjà un INSERT EXEC, cela ne fonctionnera pas.
MOHCTP
46

Vous devez lire sur OPENROWSET et OPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
Rizwan Mumtaz
la source
4
Comment obtenir dynamiquement YOURSERVERNAME? Vous ne pouvez pas vous attendre à devoir toujours savoir. Est-ce que cette pause ne se fera pas un mardi sur deux? Donc, si j'ai 100 serveurs tous avec des noms différents ...
Urasquirrel
Et si ma base de données n'est pas configurée pour permettre cela?
Urasquirrel
4
Essayez @@ nomserveur pour l'obtenir dynamiquement
Siddhartha Gandhi
44

Vous devez déclarer un type de table qui contient le même nombre de colonnes que votre procédure de stockage renvoie. Les types de données des colonnes dans le type de table et les colonnes retournées par les procédures doivent être identiques

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

Ensuite, vous devez insérer le résultat de votre procédure stockée dans le type de table que vous venez de définir

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

En fin de compte, sélectionnez simplement votre type de table

Select * from @MyTableType
Aamir
la source
C'est la meilleure solution pour moi, car vous n'avez pas besoin de spécifier le nom du serveur, les chaînes de connexion ou de configurer des serveurs liés pour le faire fonctionner - ce que je ne veux pas faire juste pour obtenir certaines données en arrière. Je vous remercie! Super réponse!
Matt
Belle réponse ღ❤ ೋ ღ❤ღ ೋ❤ ღ
Nahid
Lorsque la procédure stockée est trop difficile - cette méthode ne fonctionne pas, par exemple, lorsque la procédure stockée utilise deux tables temporaires.
nick_n_a
34

Il n'est pas nécessaire d'utiliser une table temporaire.

C'est ma solution

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue
DavideDM
la source
2
Cela vous oblige à ajouter votre serveur en tant que serveur lié à lui-même, mais cela fonctionne comme un charme! Merci!
vaheeds
Quelques bonnes mises en garde à ce sujet: stackoverflow.com/questions/2374741/…
Keith Adler
1
Hmm ... J'obtiens l'erreur "Erreur 7411: le serveur 'YourServerName' n'est pas configuré pour l'accès aux données." Que dois-je changer?
Matt
Avez-vous ajouté votre serveur en tant que serveur lié? YourServerName est le nom de votre serveur. Vous devez changer YourServerName avec votre vrai nom de serveur.
DavideDM
@Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
alexkovelsky
23

Vous pouvez copier la sortie de sp dans une table temporelle.

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

la source
7

utiliser OPENQUERY et avant d'exécuter l'ensemble 'SET FMTONLY OFF; SET NOCOUNT ON; '

Essayez cet exemple de code:

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

Essayez de convertir votre procédure en une fonction en ligne qui renvoie un tableau comme suit:

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

Et puis vous pouvez l'appeler comme

SELECT * FROM MyProc()

Vous avez également la possibilité de passer des paramètres à la fonction comme suit:

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

Et appelle ça

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

Si "ACCÈS AUX DONNÉES" est faux,

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

après,

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

Ça marche.

Ali Osman Yavuz
la source
5

Vous pouvez tricher un peu avec OPENROWSET:

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

Bien sûr, cela exécuterait tout le SP à chaque fois.

MartW
la source
4

Par souci de simplicité et pour le rendre réexécutable, j'ai utilisé un système StoredProcedure "sp_readerrorlog" pour obtenir les données:

-----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
Sheikh Kawser
la source
1

Il semble que vous ayez simplement besoin d'utiliser une vue . Une vue permet à une requête d'être représentée sous forme de table afin qu'elle, la vue, puisse être interrogée.

Lawrence Barsanti
la source
1

Si votre serveur s'appelle SERVERX par exemple, c'est comme ça que je l'ai fait ...

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

Pour vérifier que cela a fonctionné, j'ai commenté la EXEC()ligne de commande et l' ai remplacée par SELECT @CMDpour revoir la commande avant d'essayer de l'exécuter! C'était pour s'assurer que tout le nombre correct de guillemets simples était au bon endroit. :-)

J'espère que cela aide quelqu'un.

Fandango68
la source