2009-09-29 8 views
223

J'ai une procédure stockée qui renvoie des lignes:SQL Server - SELECT de la procédure stockée

CREATE PROCEDURE MyProc 
AS 
BEGIN 
    SELECT * FROM MyTable 
END 

Ma procédure actuelle est un peu plus compliqué, ce qui explique 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 

Je dois utiliser SELECT TOP X, ROW_NUMBER, et une clause WHERE supplémentaire à la page mes données, et je ne veux pas vraiment de transmettre ces valeurs en tant que paramètres.

+0

Je ne suis pas sûr de ce que vous avez l'intention de le faire ici parce que quand vous exécutez la procédure, vous récupérez les lignes. Est-ce que vous voulez exécuter la procédure dans une instruction SELECT pour pouvoir l'attacher à un objet paginable? –

+1

Y a-t-il une raison particulière pour laquelle vous ne voulez pas transmettre les valeurs en tant que paramètres? Le faire de la manière que vous suggérez est un peu inefficace - vous choisiriez plus de données que vous n'en avez besoin, et vous n'utiliserez pas tout cela. –

+2

Jetez un oeil à: http://www.sommarskog.se/share_data.html – pylover

Répondre

105

Vous pouvez utiliser un User-defined function ou view au lieu d'une procédure. Une procédure peut renvoyer plusieurs ensembles de résultats, chacun avec son propre schéma. Il ne convient pas à l'utilisation dans une instruction SELECT.

+6

En outre, si après la conversion en UDF vous avez besoin de la sémantique de la procédure stockée, vous pouvez toujours enrouler le UDF avec une procédure. –

+0

et si nous devions envoyer des paramètres à plusieurs procédures stockées et les combiner en une grande procédure stockée? Peut afficher, prendre des paramètres, comme les procédures stockées – mrN

+3

@mrN Les vues ne prennent pas de paramètres, contrairement aux UDF. –

62

Soit vous voulez un Table-Valued function ou insérez votre EXEC dans une table temporaire:

INSERT INTO #tab EXEC MyProc 
+22

Le problème avec 'INSERT # T' ou' INSERT @ T' est qu'une instruction 'INSERT EXEC' ne peut pas être imbriquée. Si la procédure stockée contient déjà un 'INSERT EXEC', cela ne fonctionnera pas. – MOHCTP

117

Vous pouvez

  1. créer une variable de table pour tenir le résultat fixé à partir du proc et stockés puis
  2. insérer la sortie de la procédure stockée dans la variable de table, puis
  3. utiliser la variable de table exactement comme vous le feriez pour tout autre table ...

... sql ....

Declare @T Table ([column definitions here]) 
Insert @T Exec storedProcname params 
Select * from @T Where ... 
+22

Le problème avec 'INSERT # T' ou' INSERT @ T' est qu'une instruction 'INSERT EXEC' ne peut pas être imbriquée. Si la procédure stockée contient déjà un 'INSERT EXEC', cela ne fonctionnera pas. – MOHCTP

+1

C'est probablement la solution la plus portable, étant la plus proche du SQL de base. Cela aide également à maintenir de solides définitions de type de colonne. Devrait avoir plus de votes upvotes que ceux ci-dessus. –

+0

Les [variables de table] (https://www.simple-talk.com/sql/t-sql-programming/temporary-tables-in-sql-server/) semblent plus utiles ici que les tables temporaires en termes de sp recompile . Donc je suis d'accord, cette réponse devrait avoir plus de votes upvotes. – resnyanskiy

2

On dirait que vous pourriez avoir besoin d'utiliser un view . Une vue permet à une requête d'être représentée sous la forme d'une table afin que la vue puisse être interrogée.

18

Vous pouvez copier la sortie de sp vers la table temporaire.

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 
127

Vous devriez regarder cet excellent article par Erland Sommarskog:

Il énumère essentiellement toutes les options disponibles pour votre scénario.

+2

Cela devrait vraiment être la réponse acceptée. L'article référencé est très complet. – ssmith

+1

Très bonne référence, je peux me voir y revenir depuis longtemps. –

+0

Excellente réponse, merci! –

4

Vous pouvez tricher un peu avec OPENROWSET:

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

Ce serait encore courir tout le SP à chaque fois, bien sûr.

33

Vous devez lire au sujet OPENROWSET et OPENQUERY

SELECT * 
INTO #tmp FROM  
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters') 
30

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

C'est ma solution

SELECT * FROM  
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters') 
WHERE somefield = anyvalue 
+1

Cela vous oblige à ajouter votre serveur en tant que serveur lié à lui-même, mais cela fonctionne comme un charme! Merci! – vaheeds

+0

Quelques grandes mises en garde à ce sujet: http://stackoverflow.com/questions/2374741/why-is-usus-openquery-on-a-local-server-bad –

+0

Hmm ... Je reçois l'erreur "Erreur 7411: Le serveur 'YourServerName' n'est pas configuré pour DATA ACCESS. " De quoi ai-je besoin pour changer? – Matt

2

Essayez de convertir votre procédure pour une fonction inline qui retourne une table 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 appelez-

SELECT * FROM FuncName (@para1 , @para2) 
14

Vous devez déclarer un type de table qui contient le même nombre de colonnes de votre procédure de magasin est de retour. Les types de données des colonnes du type de table et les colonnes retournées par les procédures devraient être les mêmes

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

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

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

à la fin il suffit de sélectionner votre type de table

Select * from @MyTableType 
+0

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 récupérer des données. Je vous remercie! Bonne réponse! – Matt

5

utilisation OPENQUERY et befor Execute set « 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 ') 
0

Si votre serveur est appelé ServerX par exemple, voici comment 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 cela a fonctionné, je commentais la ligne de commande et l'a remplacé par SELECT @CMD pour examiner la commande avant d'essayer de l'exécuter! C'était pour s'assurer que tout le bon nombre de guillemets simples était au bon endroit. :-)

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

2

Si false 'ACCESS DATA',

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

après,

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

cela fonctionne.

1

Par souci de simplicité et de le faire re-runnable, j'ai utilisé un système StoredProcedure « sp_readerrorlog » pour obtenir des 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 
Questions connexes