SQL Server - SELECT FROM procedimento armazenado

334

Eu tenho um procedimento armazenado que retorna linhas:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Meu procedimento atual é um pouco mais complicado, e é por isso que um broche é necessário.

É possível selecionar a saída chamando este procedimento?

Algo como:

SELECT * FROM (EXEC MyProc) AS TEMP

Eu preciso usar SELECT TOP X, ROW_NUMBERe um adicional WHEREcláusula para a página meus dados, e eu realmente não quero passar esses valores como parâmetros.

jonathanpeppers
fonte
Não tenho certeza do que você pretende fazer aqui, porque quando você executa o procedimento, está recuperando as linhas. Você deseja executar o procedimento dentro de uma instrução SELECT para amarrá-lo a um objeto paginável?
22499 Raj Mais
1
Existe uma razão específica para você não querer passar os valores como parâmetros? Fazer isso da maneira que você está sugerindo é um pouco ineficiente - você selecionaria mais dados do que o necessário e depois não usaria tudo.
22430 Mark Bell
2
Dê uma olhada aqui: sommarskog.se/share_data.html
pylover

Respostas:

149

Você pode usar uma função definida pelo usuário ou uma exibição em vez de um procedimento.

Um procedimento pode retornar vários conjuntos de resultados, cada um com seu próprio esquema. Não é adequado para uso em uma SELECTdeclaração.

Mehrdad Afshari
fonte
8
Além disso, se após a conversão para um UDF você achar que precisa da semântica do procedimento armazenado, sempre poderá agrupar o UDF com um procedimento.
Joel Coehoorn
e se precisarmos enviar parâmetros para vários procedimentos armazenados e combiná-los em um único procedimento armazenado? Pode ver, os parâmetros de tomar, como procedimentos armazenados faz
MRN
3
As visualizações @mrN não aceitam parâmetros, mas UDFs sim.
Mehrdad Afshari
3
Olá, eu realmente preciso fazer isso sem converter o sp em uma exibição ou função, é possível?
Luis Becerril
2
Embora sua resposta seja uma afirmação verdadeira, ela não responde à pergunta .... "SELECT FROM procedure armazenada" Que certeza não é o ideal, mas é o que é ... @ A resposta de Aamir é a resposta correta. Ou isso ou a questão precisa ser mudada ... o que me parece um pouco ridículo.
Urasquirrel
202

Você pode

  1. crie uma variável de tabela para armazenar o conjunto de resultados do proc armazenado e, em seguida,
  2. insira a saída do proc armazenado na variável da tabela e, em seguida,
  3. use a variável de tabela exatamente como faria com qualquer outra tabela ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...
Charles Bretana
fonte
34
O problema com INSERT #Tou INSERT @Té que uma INSERT EXECinstrução não pode ser aninhada. Se o procedimento armazenado já tiver um INSERT EXEC, isso não funcionará.
MOHCTP
2
Esta é provavelmente a solução mais portátil, estando mais próxima do SQL básico. Também ajuda a manter fortes definições de tipo de coluna. Deveria ter mais votos positivos do que aqueles acima.
As variáveis ​​de tabela parecem mais úteis aqui do que as tabelas temporárias em termos de recompilação sp. Então, eu concordo, essa resposta deve ter mais votos positivos.
resnyanskiy 16/03/19
76

Você deseja uma função com valor de tabela ou insere seu EXEC em uma tabela temporária:

INSERT INTO #tab EXEC MyProc
CMerat
fonte
32
O problema com INSERT #Tou INSERT @Té que uma INSERT EXECinstrução não pode ser aninhada. Se o procedimento armazenado já tiver um INSERT EXEC, isso não funcionará.
MOHCTP
46

Você deve ler sobre o OPENROWSET e OPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
Rizwan Mumtaz
fonte
4
Como obter YOURSERVERNAME dinamicamente? Você não pode esperar ter que saber sempre. Isso não será interrompido toda terça-feira? Então, se eu tenho 100 servidores, todos com nomes diferentes ...
Urasquirrel
e também se meu banco de dados não estiver configurado para permitir isso?
Urasquirrel
4
Tente @@ servername para obtê-lo dinamicamente #
Siddhartha Gandhi
44

Você precisa declarar um tipo de tabela que contém o mesmo número de colunas que seu procedimento de armazenamento está retornando. Os tipos de dados das colunas no tipo de tabela e as colunas retornadas pelos procedimentos devem ser os mesmos

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

Então você precisa inserir o resultado do seu procedimento armazenado no tipo de tabela que você acabou de definir

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

No final, basta selecionar do seu tipo de mesa

Select * from @MyTableType
Aamir
fonte
Essa é a melhor solução para mim, porque você não precisa especificar o nome do servidor, as cadeias de conexão ou precisa configurar quaisquer servidores vinculados para fazê-lo funcionar - que são coisas que não quero fazer apenas para obter alguns dados de volta. Obrigado! Resposta impressionante!
Matt
Resposta agradável ღ❤ ೋ ღ❤ღ ೋ❤ ღ
Nahid
Quando o procedimento armazenado é muito difícil - esse método não funciona, por exemplo, quando o procedimento armazenado usa duas tabelas temporárias.
nick_n_a
34

Não é necessário usar uma tabela temporária.

Esta é a minha solução

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue
DavideDM
fonte
2
Isso precisa que você adicione seu servidor como um servidor vinculado a si mesmo, mas funciona como um encanto! obrigado!
vaheeds
Algumas grandes advertências sobre isso: stackoverflow.com/questions/2374741/…
Keith Adler
1
Hmm ... Estou recebendo o erro "Erro 7411: O servidor 'YourServerName' não está configurado para ACESSO DE DADOS." O que eu preciso mudar?
Matt
Você adicionou seu servidor como um servidor vinculado? YourServerName é o nome do seu servidor. Você precisa alterar YourServerName com o nome real do servidor.
DavideDM
@Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
alexkovelsky
23

Você pode copiar a saída de sp para a tabela temporária.

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

fonte
7

use OPENQUERY e antes de executar o conjunto 'SET FMTONLY OFF; DEFINIR NOCOUNT ON; '

Tente este código de exemplo:

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

Tente converter seu procedimento em uma função embutida que retorne uma tabela da seguinte maneira:

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

E então você pode chamá-lo como

SELECT * FROM MyProc()

Você também tem a opção de passar parâmetros para a função da seguinte maneira:

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

E chame

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

Se 'DATA ACCESS' for falso,

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

depois de,

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

funciona.

Ali Osman Yavuz
fonte
5

Você pode trapacear um pouco com OPENROWSET:

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

Isso ainda executaria todo o SP toda vez, é claro.

MartW
fonte
4

Por uma questão de simplicidade e para torná-lo executável novamente, usei o sistema StoredProcedure "sp_readerrorlog" para obter dados:

-----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
fonte
1

Parece que você pode precisar apenas usar uma visualização . Uma visão permite que uma consulta seja representada como uma tabela para que a visão possa ser consultada.

Lawrence Barsanti
fonte
1

Se o seu servidor se chama SERVERX, por exemplo, foi assim que eu fiz ...

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 verificar isso funcionou, comentei a EXEC()linha de comando e a substitui porSELECT @CMD a por revisar o comando antes de tentar executá-lo! Isso foi para garantir que todo o número correto de aspas simples estivesse no lugar certo. :-)

Espero que ajude alguém.

Fandango68
fonte