Eu tenho três procedimentos armazenados Sp1
, Sp2
e Sp3
.
O primeiro ( Sp1
) executará o segundo ( Sp2
) e salvará os dados retornados no @tempTB1
e o segundo executará o terceiro ( Sp3
) e salvará os dados no @tempTB2
.
Se eu executar o Sp2
ele funcionará e ele retornará todos os meus dados do Sp3
, mas o problema está no Sp1
, quando eu executar ele exibirá este erro:
A instrução INSERT EXEC não pode ser aninhada
Tentei mudar o local de execute Sp2
e ele me mostrou outro erro:
Não é possível usar a instrução ROLLBACK em uma instrução INSERT-EXEC.
fonte
sp_help_jobactivity
).Esta é a única maneira "simples" de fazer isso no SQL Server sem alguma função criada complicada gigante ou chamada de string sql executada, sendo que ambas são soluções terríveis:
EXEMPLO:
Nota : Você DEVE usar 'set fmtonly off' E NÃO PODE adicionar sql dinâmico a ele dentro da chamada openrowset, seja para a string contendo seus parâmetros de procedimento armazenado ou para o nome da tabela. É por isso que você deve usar uma tabela temporária em vez de variáveis de tabela, o que teria sido melhor, já que executa uma tabela temporária na maioria dos casos.
fonte
OK, encorajado por Jimhark, aqui está um exemplo da antiga abordagem de tabela hash única: -
fonte
Minha solução para esse problema sempre foi usar o princípio de que tabelas temporárias de hash simples estão no escopo de qualquer procs chamada. Então, eu tenho um switch de opção nos parâmetros proc (padrão definido como off). Se estiver ativado, o proc chamado irá inserir os resultados na tabela temporária criada no proc de chamada. Acho que no passado eu dei um passo adiante e coloquei algum código no proc chamado para verificar se a tabela hash única existe no escopo, se existir, então insira o código, caso contrário, retorne o conjunto de resultados. Parece funcionar bem - a melhor maneira de passar grandes conjuntos de dados entre procs.
fonte
Este truque funciona para mim.
Você não tem esse problema no servidor remoto, porque no servidor remoto, o último comando de inserção aguarda o resultado do comando anterior para ser executado. Não é o caso no mesmo servidor.
Aproveite essa situação para uma solução alternativa.
Se você tiver a permissão certa para criar um servidor vinculado, faça isso. Crie o mesmo servidor como servidor vinculado.
agora seu comando Sql no SP1 é
Acredite em mim, funciona mesmo que você tenha um insert dinâmico no SP2
fonte
Eu descobri que uma solução alternativa é converter um dos prods em uma função com valor de tabela. Percebo que nem sempre é possível e apresenta suas próprias limitações. No entanto, sempre consegui encontrar pelo menos um dos procedimentos um bom candidato para isso. Gosto desta solução porque não introduz nenhum "hacks" na solução.
fonte
Eu encontrei esse problema ao tentar importar os resultados de um Stored Proc em uma tabela temporária e que Stored Proc inseriu em uma tabela temporária como parte de sua própria operação. O problema é que o SQL Server não permite que o mesmo processo grave em duas tabelas temporárias diferentes ao mesmo tempo.
A resposta aceita do OPENROWSET funciona bem, mas eu precisava evitar o uso de SQL dinâmico ou um provedor OLE externo em meu processo, então fui por um caminho diferente.
Uma solução alternativa fácil que descobri foi alterar a tabela temporária em meu procedimento armazenado para uma variável de tabela. Ele funciona exatamente da mesma forma que funcionava com uma mesa temporária, mas não entra mais em conflito com minha outra inserção de tabela temporária.
Só para evitar o comentário, sei que alguns de vocês estão prestes a escrever, avisando-me que as Variáveis de Tabela são destruidoras de desempenho ... Tudo o que posso dizer a vocês é que em 2020 vale a pena não ter medo das Variáveis de Tabela. Se estivéssemos em 2008 e meu banco de dados estivesse hospedado em um servidor com 16 GB de RAM e HDDs de 5400 RPM, talvez eu concorde com você. Mas é 2020 e tenho uma matriz SSD como meu armazenamento principal e centenas de GB de RAM. Eu poderia carregar o banco de dados de toda a minha empresa em uma variável de tabela e ainda ter bastante RAM de sobra.
As variáveis de tabela estão de volta ao menu!
fonte
Eu tive o mesmo problema e preocupação com código duplicado em dois ou mais sprocs. Acabei adicionando um atributo adicional para "modo". Isso permitiu a existência de código comum dentro de um sproc e do fluxo direcionado de modo e conjunto de resultados do sproc.
fonte
que tal apenas armazenar a saída na tabela estática? Gostar
não é o ideal, mas é tão simples e você não precisa reescrever tudo.
ATUALIZAÇÃO : a solução anterior não funciona bem com consultas paralelas (acesso assíncrono e multiusuário), portanto agora estou usando tabelas temporárias
spGetData
conteúdo de procedimento armazenado aninhadofonte
Declare uma variável de cursor de saída para o sp interno:
Em seguida, declare um cursor c para a seleção que deseja retornar. Em seguida, abra o cursor. Em seguida, defina a referência:
NÃO feche ou realoque.
Agora chame o sp interno do externo fornecendo um parâmetro de cursor como:
Depois que o sp interno for executado, você
@cOUT
estará pronto para buscar. Faça um loop, feche e desaloque.fonte
Se você puder usar outras tecnologias associadas, como C #, sugiro usar o comando SQL integrado com o parâmetro Transaction.
Eu criei um aplicativo de console simples que demonstra essa capacidade que pode ser encontrado aqui: https://github.com/hecked12/SQL-Transaction-Using-C-Sharp
Resumindo, C # permite que você supere essa limitação onde você pode inspecionar a saída de cada procedimento armazenado e usar essa saída como quiser, por exemplo, você pode alimentá-la para outro procedimento armazenado. Se a saída estiver ok, você pode confirmar a transação, caso contrário, você pode reverter as alterações usando rollback.
fonte
No SQL Server 2008 R2, tive uma incompatibilidade nas colunas da tabela que causou o erro de reversão. Ele foi embora quando eu corrigi minha variável de tabela sqlcmd preenchida pela instrução insert-exec para corresponder àquela retornada pelo proc armazenado. Estava faltando org_code. Em um arquivo cmd do Windows, ele carrega o resultado do procedimento armazenado e o seleciona.
fonte