Inserir nos valores ... ( SELECT ... FROM ... )

Eu estou tentando INSERT INTO uma tabela utilizando a entrada de outra tabela. Embora isto seja inteiramente viável para muitos motores de banco de dados, eu sempre pareço ter dificuldade para lembrar a sintaxe correta para o motor SQL do dia (MySQL, Oracle, SQL Server, Informix, e DB2).

Existe uma sintaxe silver-bullet proveniente de um padrão SQL (por exemplo, SQL-92) que me permitiria inserir os valores sem me preocupar com a base de dados subjacente?

Solução

Tente:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

Este é o ANSI SQL padrão e deve funcionar em qualquer SGBD

Definitivamente funciona para:

  • Oracle
  • MS SQL Server
  • MySQL
  • Postgres
  • SQLite v3
  • Teradata
  • DB2
  • Sybase
  • Vertica
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA
Comentários (0)

@Shadow_x99: Isso deve funcionar bem, e você também pode ter várias colunas e outros dados:

INSERT INTO table1 ( column1, column2, someInt, someVarChar )
SELECT  table2.column1, table2.column2, 8, 'some string etc.'
FROM    table2
WHERE   table2.ID = 7;

Editar: Devo mencionar que só utilizei esta sintaxe com Access, SQL 2000/2005/Express, MySQL e PostgreSQL, por isso estas devem ser cobertas. Um comentador apontou que vai funcionar com o SQLite3.

Comentários (2)

Ambas as respostas que eu vejo funcionam bem no Informix especificamente, e são basicamente SQL padrão. Ou seja, a notação:

INSERT INTO target_table[()] SELECT ... FROM ...;

funciona bem com Informix e, eu esperaria, com todo o SGBD. (Há 5 ou mais anos atrás, este é o tipo de coisa que o MySQL nem sempre suportava; agora tem um suporte decente para este tipo de sintaxe SQL padrão e, AFAIK, funcionaria bem nesta notação). A lista de colunas é opcional mas indica as colunas alvo em sequência, por isso a primeira coluna do resultado do SELECT irá para a primeira coluna listada, etc. Na ausência da lista de colunas, a primeira coluna do resultado do SELECT vai para a primeira coluna da tabela de destino.

O que pode ser diferente entre sistemas é a notação utilizada para identificar tabelas em diferentes bases de dados - o padrão não tem nada a dizer sobre operações inter-bases de dados (quanto mais inter-DBMS). Com Informix, você pode usar a seguinte notação para identificar uma tabela:

[dbase[@server]:][owner.]table

Ou seja, você pode especificar uma base de dados, opcionalmente identificando o servidor que hospeda essa base de dados se ela não estiver no servidor atual, seguido por um proprietário opcional, ponto, e finalmente o nome real da tabela. O padrão SQL usa o termo esquema para o que o Informix chama de proprietário. Assim, no Informix, qualquer uma das seguintes notações poderia identificar uma tabela:

table
"owner".table
dbase:table
dbase:owner.table
dbase@server:table
dbase@server:owner.table

O proprietário em geral não precisa ser citado; no entanto, se você usar citações, você precisa obter o nome do proprietário soletrado corretamente - ele se torna sensível a maiúsculas e minúsculas. Isto é, o nome do proprietário é sensível a maiúsculas e minúsculas:

someone.table
"someone".table
SOMEONE.table

todos identificam a mesma tabela. Com o Informix, há uma pequena complicação com as bases de dados MODE ANSI, onde os nomes dos proprietários são geralmente convertidos para maiúsculas (informmix é a exceção). Ou seja, em um banco de dados MODE ANSI (não comumente utilizado), você poderia escrever:

CREATE TABLE someone.table ( ... )

e o nome do proprietário no catálogo do sistema seria "ALGUÉM", em vez de "alguém". Se você incluir o nome do proprietário entre aspas duplas, ele age como um identificador delimitado. Com SQL padrão, os identificadores delimitados podem ser usados em muitos lugares. Com Informix, você pode usá-los apenas em torno de nomes de proprietários -- em outros contextos, Informix trata tanto strings com aspas simples quanto com aspas duplas como strings, em vez de separar strings com aspas simples como strings e strings com aspas duplas como identificadores delimitados. (Claro, apenas para completar, existe uma variável de ambiente, DELIMIDENT, que pode ser definida - para qualquer valor, mas Y é o mais seguro - para indicar que aspas duplas sempre rodeiam identificadores delimitados e aspas simples sempre rodeiam strings).

Note que o MS SQL Server consegue utilizar [identificadores delimitados] entre parênteses rectos. Parece-me estranho, e certamente não faz parte do padrão SQL.

Comentários (0)