Eu tenho um proc armazenado spGetSites que retorna três colunas para SiteName, SiteId e UnitCount. O proc armazenado funciona perfeitamente bem. Estou tentando armazenar os resultados do procedimento armazenado em uma tabela temporária @Site para usar em meu relatório com a sintaxe abaixo. Desta vez, recebi uma mensagem de erro: “Instrução INSERT EXEC não pode ser aninhada”
Não posso usar as instruções INSERT e EXEC ao mesmo tempo?
DECLARE @Site TABLE (SiteName VARCHAR(100), SiteId INT, UnitCount INT) INSERT INTO @Site EXEC spGetSites @SiteId = 0
Comentários
- Você deve , dbfiddle.uk/… Adicione seu procedimento armazenado à pergunta e marque sua versão do SQL Server.
Resposta
Se você olhar o código do seu spGetSites
procedimento, em algum lugar nesse procedimento está outro INSERT...EXEC
. Pode ser diretamente nesse procedimento, ou aninhado nas entranhas de algum outro procedimento que ele chama.
Em última análise, se um procedimento armazenado usar INSERT...EXEC
, se você tentar chamar esse procedimento armazenado no contexto de outro INSERT...EXEC
, você obterá o erro que está vendo .
Como você corrige?
-
Você poderia simplesmente pegar o
INSERT...EXEC
interno e embutir o código para isso procedimento armazenado único. Porém, eu suspeito que outro procedimento pode estar lá por um motivo: ou seja, para manter seu código SECO. -
Uma vez que este é um
Get
procedimento, esperançosamente não há manipulação de dados acontecendo em qualquer lugar na pilha de chamadas. Você poderia converter o procedimento filho em uma função com valor de tabela. Isso permitiria a você converter aqueleINSERT...EXEC
interno em umINSERT...SELECT
e resolva esse problema. -
Use tabelas temporárias com escopo para o procedimento externo para passar dados entre os procedimentos. Esta solução obtém complicado, por isso não é o meu favorito e geralmente desencorajo esse padrão quando há uma opção melhor – mas por uma questão de integridade, vou incluí-lo aqui. Basicamente, se você criar sua tabela #temp fora de
spGetSites
, poderá usá-la dentro despGetSites
(sem criá-la lá dentro) e da tabela com os dados inseridos sobreviverá à execução do procedimento e continuará a funcionar.
Não gosto da opção 3 porque é um padrão de codificação complexo o suficiente para garantir que alguém bagunce tudo no futuro, a menos que todos estejam a bordo e familiarizados com a codificação padrão: * spGetSites
falhará a menos que você crie a tabela primeiro. Todos os chamadores precisam se lembrar de criar a tabela exatamente da mesma primeiro. * spGetSites
não pode “presumir que a tabela está vazia. Ela pode ter dados existentes da chamada externa (ou uma execução anterior do mesmo chamador) * Solução de problemas e depuração (e até mesmo obter um plano de consulta) para spGetSites
é mais complexo por causa da confusão na criação da tabela.
O que eu faria?
Sem saber o quão complexo o o código está por trás de spGetSites
, eu “daria uma olhada na criação de um TVF embutido que substitua o INSERT...EXEC
interno por INSERT...SELECT
ou possivelmente todo o spGetSites
poderia ser simplificado / reescrito para torná-lo autocontido sem o INSERT...EXEC