Como eu faço um SELECT * INTO [temp table] FROM [stored procedure]
? Não FROM [Table]
e sem definir [temp table]
?
Select
todos os dados do BusinessLine
para dentro tmpBusLine
funcionam bem.
select *
into tmpBusLine
from BusinessLine
Estou tentando o mesmo, mas usando um stored procedure
que retorna dados, não é exatamente o mesmo.
select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'
Mensagem de saída:
Msg 156, Nível 15, Estado 1, Linha 2 Sintaxe incorreta perto da palavra-chave 'exec'.
Li vários exemplos de criação de uma tabela temporária com a mesma estrutura que o procedimento armazenado de saída, que funciona bem, mas seria bom não fornecer nenhuma coluna.
Respostas:
Você pode usar o OPENROWSET para isso. Dar uma olhada. Também incluí o código sp_configure para ativar as consultas distribuídas ad hoc, caso ainda não esteja ativado.
fonte
Se você quiser fazer isso sem declarar primeiro a tabela temporária, tente criar uma função definida pelo usuário em vez de um procedimento armazenado e faça com que essa função definida pelo usuário retorne uma tabela. Como alternativa, se você deseja usar o procedimento armazenado, tente algo como isto:
fonte
No SQL Server 2005, você pode usar
INSERT INTO ... EXEC
para inserir o resultado de um procedimento armazenado em uma tabela. Na documentação do MSDNINSERT
(para o SQL Server 2000, de fato):fonte
Esta é uma resposta para uma versão ligeiramente modificada da sua pergunta. Se você pode abandonar o uso de um procedimento armazenado para uma função definida pelo usuário, pode usar uma função definida pelo usuário embutida com valor de tabela. Este é essencialmente um procedimento armazenado (aceita parâmetros) que retorna uma tabela como um conjunto de resultados; e, portanto, colocará bem com uma declaração INTO.
Aqui está um bom artigo rápido sobre ele e outras funções definidas pelo usuário. Se você ainda precisa de um procedimento armazenado, é possível agrupar a função definida pelo usuário em linha com valor de tabela com um procedimento armazenado. O procedimento armazenado apenas passa parâmetros quando chama select * da função definida pelo usuário com valor de tabela embutido.
Por exemplo, você teria uma função definida pelo usuário em linha com valor de tabela para obter uma lista de clientes para uma região específica:
Em seguida, você pode chamar esta função para obter os resultados como:
Ou para fazer um SELECT INTO:
Se você ainda precisar de um procedimento armazenado, envolva a função da seguinte maneira:
Eu acho que este é o método mais 'hack-less' para obter os resultados desejados. Ele usa os recursos existentes, pois eles foram projetados para serem usados sem complicações adicionais. Aninhando a função definida pelo usuário em linha com valor de tabela no procedimento armazenado, você tem acesso à funcionalidade de duas maneiras. Mais! Você tem apenas um ponto de manutenção para o código SQL real.
O uso do OPENROWSET foi sugerido, mas não é para isso que a função OPENROWSET se destina a ser usada (nos Manuais Online):
O uso do OPENROWSET fará o trabalho, mas haverá uma sobrecarga adicional para abrir conexões locais e organizar dados. Também pode não ser uma opção em todos os casos, pois requer uma permissão de consulta ad hoc, que representa um risco à segurança e, portanto, pode não ser desejada. Além disso, a abordagem OPENROWSET impedirá o uso de procedimentos armazenados retornando mais de um conjunto de resultados. O agrupamento de várias funções embutidas definidas pelo usuário com valor de tabela em um único procedimento armazenado pode conseguir isso.
fonte
fonte
Se você não conhece o esquema, pode fazer o seguinte. Observe que existem riscos graves à segurança nesse método.
fonte
Quando o procedimento armazenado retorna muitas colunas e você não deseja "criar" manualmente uma tabela temporária para conter o resultado, descobri que a maneira mais fácil é entrar no procedimento armazenado e adicionar uma cláusula "into" no diretório última instrução de seleção e adicione 1 = 0 à cláusula where.
Execute o procedimento armazenado uma vez e volte e remova o código SQL que você acabou de adicionar. Agora, você terá uma tabela vazia correspondente ao resultado do procedimento armazenado. Você pode "script table as create" para uma tabela temporária ou simplesmente inserir diretamente nessa tabela.
fonte
SELECT INTO
uma tabela temporária e uma tabela de script criada a partir da tabela temporária? As tabelas temporárias aparecem,tempdb
mas não consigo clicar com o botão direito e criar um script. Qualquer ajuda é apreciada.select ... into new_table
criar implicitamente uma tabela real.declare @s varchar(max)='';select @s=@s+','+COLUMN_NAME+' '+DATA_TYPE+isnull('('+case CHARACTER_MAXIMUM_LENGTH when -1 then 'max' else cast(CHARACTER_MAXIMUM_LENGTH as varchar(10))end+')','')from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='...';select @s
fonte
Seu procedimento armazenado apenas recupera os dados ou também os modifica? Se for usado apenas para recuperar, você poderá converter o procedimento armazenado em uma função e usar as Common Table Expressions (CTEs) sem precisar declá-lo, da seguinte maneira:
No entanto, o que precisar ser recuperado do CTE deve ser usado em apenas uma instrução. Você não pode fazer um
with temp as ...
e tentar usá-lo após algumas linhas do SQL. Você pode ter vários CTEs em uma instrução para consultas mais complexas.Por exemplo,
fonte
Se a tabela de resultados do seu processo armazenado for muito complicada para digitar manualmente a instrução "create table" e você não puder usar OPENQUERY OU OPENROWSET, poderá usar sp_help para gerar a lista de colunas e tipos de dados para você. Depois de ter a lista de colunas, é apenas uma questão de formatá-la para atender às suas necessidades.
Etapa 1: adicione "na #temp" à consulta de saída (por exemplo, "selecione [...] na #temp de [...]").
A maneira mais fácil é editar a consulta de saída no proc diretamente. se você não conseguir alterar o processo armazenado, poderá copiar o conteúdo para uma nova janela de consulta e modificar a consulta lá.
Etapa 2: execute sp_help na tabela temporária. (por exemplo, "exec tempdb..sp_help #temp")
Após criar a tabela temporária, execute sp_help na tabela temporária para obter uma lista das colunas e tipos de dados, incluindo o tamanho dos campos varchar.
Etapa 3: Copie as colunas e os tipos de dados em uma instrução create table
Eu tenho uma planilha do Excel que eu uso para formatar a saída de sp_help em uma instrução "criar tabela". Você não precisa de nada tão sofisticado, basta copiar e colar no seu editor SQL. Use os nomes, tamanhos e tipos de coluna para construir uma instrução "Criar tabela nº x [...]" ou "declarar @x tabela [...]" que você pode usar para INSERIR os resultados do procedimento armazenado.
Etapa 4: Inserir na tabela recém-criada
Agora você terá uma consulta semelhante às outras soluções descritas neste segmento.
Essa técnica também pode ser usada para converter uma tabela temporária (
#temp
) em uma variável de tabela (@temp
). Embora isso possa ser mais etapas do que apenas escrever acreate table
instrução, evita erros manuais, como erros de digitação e incompatibilidade de tipos de dados em grandes processos. Depurar um erro de digitação pode levar mais tempo do que escrever a consulta em primeiro lugar.fonte
Se o OPENROWSET estiver causando problemas, existe outra maneira a partir de 2012; use sys.dm_exec_describe_first_result_set_for_object, conforme mencionado aqui: Recuperar nomes de colunas e tipos de um procedimento armazenado?
Primeiro, crie este procedimento armazenado para gerar o SQL para a tabela temporária:
Para usar o procedimento, chame-o da seguinte maneira:
Observe que estou usando uma tabela temporária global. Isso ocorre porque o uso do EXEC para executar o SQL dinâmico cria sua própria sessão; portanto, uma tabela temporária comum estaria fora do escopo de qualquer código subsequente. Se uma tabela temporária global for um problema, você poderá usar uma tabela temporária comum, mas qualquer SQL subsequente precisará ser dinâmico, ou seja, também executado pela instrução EXEC.
fonte
@SQL
.Quassnoi me levou a maior parte do caminho até lá, mas faltava uma coisa:
**** Eu precisava usar parâmetros no procedimento armazenado. ****
E o OPENQUERY não permite que isso ocorra:
Então, eu encontrei uma maneira de trabalhar com o sistema e também não tenho que tornar a definição da tabela tão rígida e redefini-la em outro procedimento armazenado (e, claro, arriscar-se).
Sim, você pode criar dinamicamente a definição de tabela retornada do procedimento armazenado usando a instrução OPENQUERY com falsos variáveis (desde que NO NO RESULT SET retorne o mesmo número de campos e na mesma posição que um conjunto de dados com bons dados).
Depois que a tabela é criada, você pode usar o procedimento armazenado exec na tabela temporária o dia inteiro.
E para observar (como indicado acima), você deve ativar o acesso a dados,
Código:
Obrigado pelas informações que foram fornecidas originalmente ... Sim, finalmente, não preciso criar todas essas definições de tabela (estritas) falsas ao usar dados de outro procedimento armazenado ou banco de dados, e sim, você também pode usar parâmetros.
Tags de referência de pesquisa:
Procedimento armazenado do SQL 2005 na tabela temporária
openquery com procedimento armazenado e variáveis 2005
openquery com variáveis
executar procedimento armazenado na tabela temporária
Atualização: isso não funcionará com tabelas temporárias, então tive que recorrer à criação manual da tabela temporária.
Aviso chatice : isso não funcionará com tabelas temporárias , http://www.sommarskog.se/share_data.html#OPENQUERY
Referência: O próximo passo é definir LOCALSERVER. Pode parecer uma palavra-chave no exemplo, mas na verdade é apenas um nome. É assim que se faz:
Para criar um servidor vinculado, você deve ter a permissão ALTER ANY SERVER ou ser membro de qualquer uma das funções fixas do servidor sysadmin ou setupadmin.
OPENQUERY abre uma nova conexão com o SQL Server. Isso tem algumas implicações:
O procedimento que você chama com OPENQUERY não pode consultar tabelas temporárias criadas na conexão atual.
A nova conexão possui seu próprio banco de dados padrão (definido com sp_addlinkedserver, o padrão é mestre), portanto, toda especificação de objeto deve incluir um nome de banco de dados.
Se você tiver uma transação aberta e estiver retendo bloqueios ao ligar para OPENQUERY, o procedimento chamado não poderá acessar o que você bloqueou. Ou seja, se você não for cuidadoso, irá se bloquear.
A conexão não é de graça, portanto há uma penalidade de desempenho.
fonte
SELECT @@SERVERNAME
. Você também pode usarEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Se você tiver a sorte de ter o SQL 2012 ou superior, poderá usar
dm_exec_describe_first_result_set_for_object
Acabei de editar o sql fornecido pelo gotqn. Obrigado gotqn.
Isso cria uma tabela temporária global com o mesmo nome que o nome do procedimento. A tabela temporária pode ser usada posteriormente, conforme necessário. Só não se esqueça de largar antes de executar novamente.
fonte
sys.all_objects
vez desys.procedures
se você quiser fazer isso para procedimentos armazenados internos.Este procedimento armazenado faz o trabalho:
É um pequeno retrabalho disso: insira os resultados do procedimento armazenado na tabela para que realmente funcione.
Se você deseja que ele funcione com uma tabela temporária, precisará usar uma
##GLOBAL
tabela e soltá-la posteriormente.fonte
Para inserir o primeiro conjunto de registros de um procedimento armazenado em uma tabela temporária, você precisa saber o seguinte:
sp_executesql
)O exemplo acima pode parecer uma limitação, mas IMHO faz perfeitamente sentido - se você estiver usando,
sp_executesql
poderá retornar duas colunas e uma vez dez e, se tiver vários conjuntos de resultados, não poderá inseri-los em várias tabelas também - poderá inserir o máximo em duas tabelas em uma instrução T-SQL (usando aOUTPUT
cláusula e sem gatilhos).Portanto, a questão é principalmente como definir a estrutura da tabela temporária antes de executar a
EXEC ... INTO ...
instrução.O primeiro funciona com
OBJECT_ID
enquanto o segundo e o terceiro também funcionam com consultas ad-hoc. Prefiro usar o DMV em vez do sp, pois você pode usarCROSS APPLY
e criar as definições da tabela temporária para vários procedimentos ao mesmo tempo.Além disso, preste atenção ao
system_type_name
campo, pois pode ser muito útil. Ele armazena a definição completa da coluna. Por exemplo:e você pode usá-lo diretamente na maioria dos casos para criar a definição da tabela.
Portanto, acho que na maioria dos casos (se o procedimento armazenado corresponder a determinados critérios), você poderá criar facilmente instruções dinâmicas para resolver esses problemas (criar a tabela temporária, inserir o resultado do procedimento armazenado, fazer o que for necessário com os dados) .
Observe que os objetos acima falham ao definir os dados do primeiro conjunto de resultados em alguns casos, como quando instruções T-SQL dinâmicas são executadas ou tabelas temporárias são usadas no procedimento armazenado.
fonte
Agora eu sei qual é o resultado do meu procedimento, então estou executando a seguinte consulta.
VALUES (10, 5, 1, NULL) SET IDENTITY_INSERT [dbo]. [TblTestingTree] Ativado
fonte
Se a consulta não contiver parâmetro, use
OpenQuery
else useOpenRowset
.O básico seria criar o esquema conforme o procedimento armazenado e inserir nessa tabela. por exemplo:
fonte
Código
Eu espero que isso ajude. Qualifique conforme apropriado.
fonte
Encontrei Passing Arrays / DataTables em Stored Procedures, o que pode lhe dar uma outra idéia de como você pode resolver seu problema.
O link sugere usar um parâmetro do tipo Imagem para passar para o procedimento armazenado. Em seguida, no procedimento armazenado, a imagem é transformada em uma variável de tabela que contém os dados originais.
Talvez exista uma maneira de isso ser usado com uma tabela temporária.
fonte
Eu encontrei o mesmo problema e aqui está o que fiz por sugestão da Paul . A principal parte é aqui é usar
NEWID()
para evitar que vários usuários executem os procedimentos / scripts de armazenamento ao mesmo tempo, a dor da tabela temporária global.fonte
Outro método é criar um tipo e usar PIPELINED para retornar seu objeto. Isso é limitado a conhecer as colunas no entanto. Mas tem a vantagem de poder fazer:
fonte
É um processo simples de duas etapas: - criar uma tabela temporária - inserir na tabela temporária.
Código para executar o mesmo:
fonte
Depois de pesquisar, encontrei uma maneira de criar uma tabela temporária dinamicamente para qualquer procedimento armazenado sem usar
OPENROWSET
ouOPENQUERY
usar um esquema genérico da definição de resultado do Procedimento Armazenado, especialmente quando você não é administrador de banco de dados.O servidor sql tem um processo de buit-in
sp_describe_first_result_set
que pode fornecer um esquema de qualquer conjunto de resultados de procedimentos. Criei uma tabela de esquema a partir dos resultados deste procedimento e defina manualmente todo o campo como NULLABLE.Você pode ajustar o esquema da versão do servidor SQL que está usando (se necessário).
fonte
Se você conhece os parâmetros que estão sendo passados e se não tem acesso para fazer sp_configure, edite o procedimento armazenado com esses parâmetros e o mesmo pode ser armazenado em uma tabela global ##.
fonte
Isso pode ser feito no SQL Server 2014 ou superior, desde que o procedimento armazenado retorne apenas uma tabela. Se alguém encontrar uma maneira de fazer isso para várias tabelas, eu adoraria saber sobre isso.
Isso puxa a definição da tabela retornada das tabelas do sistema e a usa para criar a tabela temporária para você. Em seguida, você pode preenchê-lo a partir do procedimento armazenado conforme indicado anteriormente.
Existem também variantes disso que também funcionam com o Dynamic SQL.
fonte
Alguns anos atrasado para a pergunta, mas eu precisava de algo assim para uma geração de código rápida e suja. Acredito que, como outros já declararam, é mais fácil definir a tabela temporária antecipadamente, mas esse método deve funcionar para consultas simples de procedimentos armazenados ou declarações sql.
Isso será um pouco complicado, mas será emprestado dos colaboradores aqui, bem como da solução de Paul White do DBA Stack Exchange Get-type de colunas de resultado do procedimento armazenado . Novamente, para reiterar essa abordagem, o exemplo não foi projetado para processos em um ambiente multiusuário. Nesse caso, a definição da tabela está sendo definida por um curto período em uma tabela temporária global para referência por um processo de modelo de geração de código.
Eu não testei completamente isso, então pode haver advertências, então você pode querer acessar o link do MSDN na resposta de Paul White. Isso se aplica ao SQL 2012 e superior.
Primeiro, use o procedimento armazenado sp_describe_first_result_set, que se assemelha à descrição do Oracle.
Isso avaliará a primeira linha do primeiro conjunto de resultados, portanto, se o procedimento armazenado ou a instrução retornar várias consultas, descreverá apenas o primeiro resultado.
Criei um proc armazenado para dividir as tarefas que retornam um único campo para selecionar e criar a definição da tabela temporária.
O enigma é que você precisa usar uma tabela global, mas precisa torná-la única o suficiente para poder abandoná-la e criá-la com frequência, sem se preocupar com uma colisão.
No exemplo, usei um Guid (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) para a variável global, substituindo os hífens por sublinhado
Novamente, eu o testei apenas com consultas simples de procedimentos armazenados e consultas simples, para que sua milhagem possa variar. Espero que isso ajude alguém.
fonte
Bem, você precisa criar uma tabela temporária, mas não precisa ter o esquema correto .... Criei um procedimento armazenado que modifica uma tabela temporária existente para que ela tenha as colunas necessárias com os dados corretos tipo e ordem (descartando todas as colunas existentes, adicionando novas colunas):
Observe que isso não funcionará se sys.dm_exec_describe_first_result_set_for_object não puder determinar os resultados do procedimento armazenado (por exemplo, se ele usar uma tabela temporária).
fonte
Se você permitir que o SQL dinâmico crie uma tabela temporária, essa tabela será de propriedade da conexão Dynamic SQL, ao contrário da conexão da qual o procedimento armazenado é chamado.
Msg 208, Nível 16, Estado 0 Nome de objeto inválido '#Pivoted'. Isso ocorre porque o #Pivoted pertence à conexão Dynamic SQL. Então a última instrução
falha.
Uma maneira de não enfrentar esse problema é garantir que todas as referências a #Pivoted sejam feitas dentro da própria consulta dinâmica:
fonte
Eu faria o seguinte
Crie (converta SP para) um UDF (valor da tabela UDF).
select * into #tmpBusLine from dbo.UDF_getBusinessLineHistory '16 Mar 2009'
fonte