SQL Server - SELECCIONAR DEL procedimiento almacenado

334

Tengo un procedimiento almacenado que devuelve filas:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Mi procedimiento real es un poco más complicado, por eso es necesario un sproc.

¿Es posible seleccionar la salida llamando a este procedimiento?

Algo como:

SELECT * FROM (EXEC MyProc) AS TEMP

Necesito usar SELECT TOP X, ROW_NUMBERy una WHEREcláusula adicional para localizar mis datos, y realmente no quiero pasar estos valores como parámetros.

jonathanpeppers
fuente
No estoy seguro de lo que piensa hacer aquí porque cuando ejecuta el procedimiento, está recuperando las filas. ¿Es que desea ejecutar el procedimiento dentro de una instrucción SELECT para poder vincularlo a un objeto paginable?
Raj More
1
¿Hay alguna razón particular por la que no desea pasar los valores como parámetros? Hacerlo de la manera que sugieres es un poco ineficaz: estarías seleccionando más datos de los que necesitas y luego no los estarías utilizando.
Mark Bell
2
Echa un vistazo aquí: sommarskog.se/share_data.html
pylover

Respuestas:

149

Puede usar una función definida por el usuario o una vista en lugar de un procedimiento.

Un procedimiento puede devolver múltiples conjuntos de resultados, cada uno con su propio esquema. No es adecuado para usar en una SELECTdeclaración.

Mehrdad Afshari
fuente
8
Además, si después de convertir a un UDF encuentra que necesita la semántica del procedimiento almacenado, siempre puede envolver el UDF con un procedimiento.
Joel Coehoorn
¿Qué sucede si necesitamos enviar parámetros a varios procedimientos almacenados y combinarlos en un único gran procedimiento almacenado? Puede ver, tomar parámetros, como lo hacen los procedimientos almacenados
mrN
3
Las vistas @mrN no toman parámetros, pero las UDF sí.
Mehrdad Afshari
3
Hola, realmente necesito hacer esto sin convertir el sp en una vista o función, ¿es posible?
Luis Becerril
2
Si bien su respuesta es una afirmación verdadera, no responde la pregunta ... "SELECCIONAR DEL procedimiento almacenado" Lo cual es seguro que no es ideal, pero es lo que es ... La respuesta de @ Aamir es la respuesta correcta. O eso o la pregunta necesita ser cambiada ... lo cual me parece un poco ridículo.
Urasquirrel
202

Usted puede

  1. crear una variable de tabla para contener el conjunto de resultados del proceso almacenado y luego
  2. inserte la salida del proceso almacenado en la variable de tabla y luego
  3. use la variable de tabla exactamente como lo haría con cualquier otra tabla ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...
Charles Bretana
fuente
34
El problema con INSERT #To INSERT @Tes que una INSERT EXECdeclaración no se puede anidar. Si el procedimiento almacenado ya tiene un INSERT EXEC, no funcionará.
MOHCTP
2
Esta es probablemente la solución más portátil, ya que está más cerca del SQL básico. También ayuda a mantener fuertes definiciones de tipo de columna. Debería tener más votos a favor que los anteriores.
Las variables de tabla parecen 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 a favor.
resnyanskiy
76

Desea una función con valores de tabla o inserte su EXEC en una tabla temporal:

INSERT INTO #tab EXEC MyProc
CMerat
fuente
32
El problema con INSERT #To INSERT @Tes que una INSERT EXECdeclaración no se puede anidar. Si el procedimiento almacenado ya tiene un INSERT EXEC, no funcionará.
MOHCTP
46

Debe leer sobre OPENROWSET y OPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
Rizwan Mumtaz
fuente
44
¿Cómo obtener YOURSERVERNAME de forma dinámica? No puedes esperar tener que saberlo siempre. ¿No se romperá este otro martes? Entonces, si tengo 100 servidores, todos con diferentes nombres ...
Urasquirrel
¿Y qué pasa si mi base de datos no está configurada para permitir esto?
Urasquirrel
44
Pruebe @@ servername para obtenerlo dinámicamente
Siddhartha Gandhi
44

Debe declarar un tipo de tabla que contenga el mismo número de columnas que devuelve su procedimiento de almacenamiento. Los tipos de datos de las columnas en el tipo de tabla y las columnas devueltas por los procedimientos deben ser iguales

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

Luego debe 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 seleccione de su tipo de tabla

Select * from @MyTableType
Aamir
fuente
Esa es la mejor solución para mí, porque no necesita especificar el nombre del servidor, las cadenas de conexión o configurar ningún servidor vinculado para que funcione, que son cosas que no quiero hacer solo para obtener algunos datos de vuelta. ¡Gracias! Impresionante respuesta!
Matt
Buena respuesta ღ❤ ೋ ღ❤ღ ೋ❤ ღ
Nahid
Cuando el procedimiento almacenado es demasiado difícil, este método no funciona, por ejemplo, cuando el procedimiento almacenado usa dos tablas temporales.
nick_n_a
34

No es necesario utilizar una tabla temporal.

Esta es mi solucion

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue
DavideDM
fuente
2
Esto necesita que agregue su servidor como un servidor vinculado a sí mismo, ¡pero funciona de maravilla! ¡Gracias!
Vaheeds
Algunas grandes advertencias sobre esto: stackoverflow.com/questions/2374741/…
Keith Adler
1
Hmm ... recibo el error "Error 7411: el servidor 'YourServerName' no está configurado para ACCESO A DATOS". ¿Qué necesito cambiar?
Matt
¿Ha agregado su servidor como un servidor vinculado? YourServerName es el nombre de su servidor. Debe cambiar YourServerName con el nombre real del servidor.
DavideDM
@Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
alexkovelsky
23

Puede copiar la salida de sp a la tabla temporal.

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

fuente
7

use OPENQUERY y antes de Ejecutar set 'SET FMTONLY OFF; SET NOCOUNT ON; '

Pruebe este código de muestra:

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

Intente convertir su procedimiento en una función en línea que devuelva una tabla de la siguiente manera:

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

Y luego puedes llamarlo 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 llámalo

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

Si 'ACCESO A DATOS' es falso,

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

después,

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

funciona.

Ali Osman Yavuz
fuente
5

Puedes engañar un poco con OPENROWSET:

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

Esto todavía correría todo el SP cada vez, por supuesto.

MartW
fuente
4

En aras de la simplicidad y para que sea ejecutable de nuevo, he utilizado un sistema 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
Sheikh Kawser
fuente
1

Parece que solo necesitas usar una vista . Una vista permite que una consulta se represente como una tabla para que se pueda consultar la vista.

Lawrence Barsanti
fuente
1

Si su servidor se llama SERVERX, por ejemplo, así es como 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 que esto funcionó, comenté la EXEC()línea de comando y la reemplacé porSELECT @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.

Fandango68
fuente