2009-09-29 48 views
223

Tengo un procedimiento almacenado que devuelve filas:SQL Server - SELECT FROM procedimiento almacenado

CREATE PROCEDURE MyProc 
AS 
BEGIN 
    SELECT * FROM MyTable 
END 

Mi procedimiento en sí es un poco más complicado, por lo que es necesario un procedimiento almacenado.

¿Es posible seleccionar la salida llamando a este procedimiento?

Algo así como:

SELECT * FROM (EXEC MyProc) AS TEMP 

necesito utilizar SELECT TOP X, ROW_NUMBER, y una cláusula adicional a la página WHERE mis datos, y yo realmente no quiero pasar estos valores como parámetros.

+0

estoy seguro de lo que va a hacer aquí porque cuando ejecutas el procedimiento, estás recuperando las filas. ¿Es que desea ejecutar el procedimiento dentro de una instrucción SELECT para que pueda vincularlo a un objeto paginable? –

+1

¿Hay algún motivo en particular por el que no desee pasar los valores como parámetros? Hacerlo de la manera que sugiere es un poco ineficiente: seleccionaría más datos de los que necesita y luego no los usaría todos. –

+2

Mire aquí: http://www.sommarskog.se/share_data.html – pylover

Respuesta

105

Se puede utilizar un User-defined function o una view en lugar de un procedimiento.

Un procedimiento puede devolver varios conjuntos de resultados, cada uno con su propio esquema. No es adecuado para usar en una declaración SELECT.

+6

Además, si después de convertir a una UDF encuentra que necesita la semántica del procedimiento almacenado, siempre puede ajustar la UDF con un procedimiento. –

+0

¿Qué sucede si tenemos que enviar parámetros a varios procedimientos almacenados y combinarlos en un solo procedimiento almacenado? Puede ver, tomar parámetros, como los procedimientos almacenados. – mrN

+3

@mrN Las vistas no toman parámetros, pero las UDF sí. –

62

O se quiere un Table-Valued function o inserte su EXEC en una tabla temporal:

INSERT INTO #tab EXEC MyProc 
+22

El problema con 'INSERT # T' o' INSERT @ T' es que una instrucción 'INSERT EXEC' no se puede anidar. Si el procedimiento almacenado ya tiene un 'INSERT EXEC', esto no funcionará. – MOHCTP

117

Usted puede

  1. crear una variable de tabla para guardar el resultado ajustar desde el procedimiento almacenado y entonces
  2. inserte la salida del proceso almacenado en la variable de tabla, y luego
  3. utilizan la variable de tabla exactamente como lo haría con cualquier otra mesa ...

... sql ....

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

El problema con 'INSERT # T' o' INSERT @ T' es que una instrucción 'INSERT EXEC' no se puede anidar. Si el procedimiento almacenado ya tiene un 'INSERT EXEC', esto no funcionará. – MOHCTP

+1

Esta es probablemente la solución más portátil, está más cerca de SQL básico. También ayuda a mantener definiciones fuertes de tipo de columna. Debería tener más votos positivos que los anteriores. –

+0

Las [variables de tabla] (https://www.simple-talk.com/sql/t-sql-programming/temporary-tables-in-sql-server/) se ven más útiles aquí que las tablas temporales en términos de recompilación sp . Así que estoy de acuerdo, esta respuesta debería tener más votos ascendentes. – resnyanskiy

2

Suena como que sólo podría necesitar usar un view . Una vista permite que una consulta se represente como una tabla para que se pueda consultar la vista.

18

Puede copiar el resultado de sp a la tabla de tiempo.

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

Usted debe mirar en este excelente artículo de Erland Sommarskog:

Básicamente enumera todas las opciones disponibles para su escenario.

+2

Esta debería ser realmente la respuesta aceptada. El artículo al que se hace referencia es muy minucioso. – ssmith

+1

Gran referencia, me veo a mí mismo volviendo a eso por mucho tiempo. –

+0

Excelente respuesta, gracias! –

4

Usted puede engañar un poco con OPENROWSET:

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

Esto a pesar de ello ejecutar toda la SP cada vez que, por supuesto.

33

usted debe leer acerca OPENROWSET y OPENQUERY

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

No es necesario, utilice una tabla temporal.

Esta es mi solución

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

Esto necesita que agregue su servidor como un servidor vinculado a sí mismo, ¡pero funciona como un encanto! ¡Gracias! – vaheeds

+0

Algunas advertencias importantes sobre esto: http://stackoverflow.com/questions/2374741/why-is-using-openquery-on-a-local-server-bad –

+0

Hmm ... Me aparece el error "Error 7411: El servidor 'YourServerName' no está configurado para DATA ACCESS. " ¿Qué necesito cambiar? – Matt

2

pruebas a convertir el procedimiento en el que una función en línea que devuelve una tabla como sigue:

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

Y entonces se le puede llamar como

SELECT * FROM MyProc() 

También tiene la opción de pasar parámetros a la función de la siguiente manera:

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

y llamarlo

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

tiene que declarar un tipo de tabla que contiene el mismo número de columnas de su proceso de almacenamiento está volviendo. Los tipos de datos de las columnas en el tipo de tabla y las columnas devueltas por los procedimientos deben ser el mismo

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

Luego hay que insertar el resultado de su procedimiento almacenado en el tipo de tabla que acaba de definir

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

al final solo tiene que seleccionar desde el tipo de tabla

Select * from @MyTableType 
+0

Esa es la mejor solución para mí, porque no necesita especificar el nombre del servidor, las cadenas de conexión o tener que configurar los servidores vinculados para que funcione, que son cosas que no quiero hacer solo para recuperar algunos datos. ¡Gracias! Impresionante respuesta! – Matt

5

uso OPENQUERY y se acaben Ejecutar conjunto 'set FMTONLY OFF; ESTABLECER NOCOUNT EN;

Prueba este código de ejemplo:

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

Si su servidor se llama SERVERx por ejemplo, esta es la forma en que lo hice ...

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

Para comprobar esto funcionó, le comenté a cabo la EXEC() línea de comando y lo reemplazó con SELECT @CMD para revisar el comando antes de intentar ejecutarlo! Eso fue para asegurarse de que todo el número correcto de comillas simples estuviera en el lugar correcto. :-)

Espero que ayude a alguien.

2

Si 'acceder a los datos falsos,

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

después,

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

funciona.

1

En aras de la simplicidad y para que sea re-ejecutable, he utilizado un sistema de StoredProcedure "sp_readerrorlog" para obtener datos:

-----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 
Cuestiones relacionadas