Inserir em… valores (SELECT… FROM…)
-
09-06-2019 - |
Pergunta
estou tentando INSERT INTO
uma tabela usando a entrada de outra tabela.Embora isso seja totalmente viável para muitos mecanismos de banco de dados, sempre pareço ter dificuldade para lembrar a sintaxe correta para o SQL
motor do dia (MySQL, Oráculo, servidor SQL, Informix, e DB2).
Existe uma sintaxe mágica proveniente de um padrão SQL (por exemplo, SQL-92) que me permitiria inserir os valores sem me preocupar com o banco de dados subjacente?
Solução
Tentar:
INSERT INTO table1 ( column1 )
SELECT col1
FROM table2
Este é o padrão ANSI SQL e deve funcionar em qualquer DBMS
Definitivamente funciona para:
- Oráculo
- Servidor SQL MS
- MySQL
- Postgres
- SQLite v3
- Teradata
- DB2
- Sybase
- vertical
- HSQLDB
- H2
- AWS RedShift
- SAP HANA
Outras dicas
@Sombra_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ó usei essa sintaxe com Access, SQL 2000/2005/Express, MySQL e PostgreSQL, portanto, eles devem ser abordados.Um comentarista apontou que funcionará com SQLite3.
Para obter apenas um valor em um valor múltiplo INSERT
de outra tabela fiz o seguinte no SQLite3:
INSERT INTO column_1 ( val_1, val_from_other_table )
VALUES('val_1', (SELECT val_2 FROM table_2 WHERE val_2 = something))
Ambas as respostas que vejo funcionam bem especificamente no Informix e são basicamente SQL padrão.Ou seja, a notação:
INSERT INTO target_table[(<column-list>)] SELECT ... FROM ...;
funciona bem com o Informix e, eu esperaria, com todos os DBMS.(Há 5 anos ou mais, esse era o tipo de coisa que o MySQL nem sempre suportava;agora tem suporte decente para esse tipo de sintaxe SQL padrão e, AFAIK, funcionaria bem nessa notação.) A lista de colunas é opcional, mas indica as colunas de destino em sequência, portanto, a primeira coluna do resultado do SELECT irá na 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 usada para identificar tabelas em diferentes bancos de dados - o padrão não tem nada a dizer sobre operações inter-bancos de dados (e muito menos inter-SGBDs).Com o Informix, você pode usar a seguinte notação para identificar uma tabela:
[dbase[@server]:][owner.]table
Ou seja, você pode especificar um banco de dados, identificando opcionalmente o servidor que hospeda esse banco de dados se ele 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 aspas, precisará escrever o nome do proprietário corretamente - ele diferencia maiúsculas de minúsculas.Aquilo é:
someone.table
"someone".table
SOMEONE.table
todos identificam a mesma tabela.Com o Informix, há uma pequena complicação com os bancos de dados MODE ANSI, onde os nomes dos proprietários são geralmente convertidos para letras maiúsculas (o Informix é a exceção).Ou seja, em um banco de dados MODE ANSI (não comumente usado), 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ê colocar o nome do proprietário entre aspas duplas, ele funcionará como um identificador delimitado.Com SQL padrão, identificadores delimitados podem ser usados em vários lugares.Com o Informix, você pode usá-los apenas em torno de nomes de proprietários - em outros contextos, o Informix trata strings entre aspas simples e aspas duplas como strings, em vez de separar strings entre aspas simples como strings e strings entre 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 é mais seguro - para indicar que aspas duplas sempre cercam identificadores delimitados e aspas simples sempre cercam strings.)
Observe que o MS SQL Server consegue usar [identificadores delimitados] entre colchetes.Parece estranho para mim e certamente não faz parte do padrão SQL.
A maioria dos bancos de dados segue a sintaxe básica,
INSERT INTO TABLE_NAME
SELECT COL1, COL2 ...
FROM TABLE_YOU_NEED_TO_TAKE_FROM
;
Cada banco de dados que usei segue esta sintaxe, ou seja, DB2
, SQL Server
, MY SQL
, PostgresQL
Para adicionar algo na primeira resposta, quando queremos apenas alguns registros de outra tabela (neste exemplo apenas um):
INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4)
VALUES (value1, value2,
(SELECT COLUMN_TABLE2
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);
Isso pode ser feito sem especificar as colunas no INSERT INTO
parte se você estiver fornecendo valores para todas as colunas no SELECT
papel.
Digamos que a tabela1 tenha duas colunas.Esta consulta deve funcionar:
INSERT INTO table1
SELECT col1, col2
FROM table2
Isso NÃO FUNCIONARIA (valor para col2
não está especificado):
INSERT INTO table1
SELECT col1
FROM table2
Estou usando o MS SQL Server.Não sei como funcionam outros RDMS.
Em vez de VALUES
parte de INSERT
consulta, basta usar SELECT
consulta como abaixo.
INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
Este é outro exemplo usando valores com select:
INSERT INTO table1(desc, id, email)
SELECT "Hello World", 3, email FROM table2 WHERE ...
Inserção simples quando a sequência das colunas da tabela é conhecida:
Insert into Table1
values(1,2,...)
Coluna de menção de inserção simples:
Insert into Table1(col2,col4)
values(1,2)
Inserção em massa quando o número de colunas selecionadas de uma tabela (#tabela2) é igual à tabela de inserção (Tabela1)
Insert into Table1 {Column sequence}
Select * -- column sequence should be same.
from #table2
Inserção em massa quando deseja inserir apenas na coluna desejada de uma tabela (tabela1):
Insert into Table1 (Column1,Column2 ....Desired Column from Table1)
Select Column1,Column2..desired column from #table2
from #table2
Aqui está outro exemplo em que a fonte é obtida usando mais de uma tabela:
INSERT INTO cesc_pf_stmt_ext_wrk(
PF_EMP_CODE ,
PF_DEPT_CODE ,
PF_SEC_CODE ,
PF_PROL_NO ,
PF_FM_SEQ ,
PF_SEQ_NO ,
PF_SEP_TAG ,
PF_SOURCE)
SELECT
PFl_EMP_CODE ,
PFl_DEPT_CODE ,
PFl_SEC ,
PFl_PROL_NO ,
PF_FM_SEQ ,
PF_SEQ_NO ,
PFl_SEP_TAG ,
PF_SOURCE
FROM cesc_pf_stmt_ext,
cesc_pfl_emp_master
WHERE pfl_sep_tag LIKE '0'
AND pfl_emp_code=pf_emp_code(+);
COMMIT;
Veja como inserir de várias tabelas.Este exemplo específico é onde você tem uma tabela de mapeamento em um cenário muitos para muitos:
insert into StudentCourseMap (StudentId, CourseId)
SELECT Student.Id, Course.Id FROM Student, Course
WHERE Student.Name = 'Paddy Murphy' AND Course.Name = 'Basket weaving for beginners'
(Sei que a correspondência no nome do aluno pode retornar mais de um valor, mas você entendeu.A correspondência com algo diferente de um Id é necessária quando o Id é uma coluna de Identidade e é desconhecido.)
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;
Isso funciona em todos os DBMS
Você poderia tentar isso se quiser inserir todas as colunas usando SELECT * INTO
mesa.
SELECT *
INTO Table2
FROM Table1;
Isso funcionou para mim:
insert into table1 select * from table2
A frase é um pouco diferente da da Oracle.
Para o Microsoft SQL Server, recomendarei aprender a interpretar a SINTAXE fornecida no MSDN.Com o Google é mais fácil do que nunca procurar sintaxe.
Para este caso específico, tente
Google:inserir site:microsoft.com
O primeiro resultado será http://msdn.microsoft.com/en-us/library/ms174335.aspx
role para baixo até o exemplo ("Usando as opções SELECT e EXECUTE para inserir dados de outras tabelas") se achar difícil interpretar a sintaxe fornecida no topo da página.
[ WITH <common_table_expression> [ ,...n ] ]
INSERT
{
[ TOP ( expression ) [ PERCENT ] ]
[ INTO ]
{ <object> | rowset_function_limited
[ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
}
{
[ ( column_list ) ]
[ <OUTPUT Clause> ]
{ VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n ]
| derived_table <<<<------- Look here ------------------------
| execute_statement <<<<------- Look here ------------------------
| <dml_table_source> <<<<------- Look here ------------------------
| DEFAULT VALUES
}
}
}
[;]
Isto deve ser aplicável a qualquer outro RDBMS disponível lá.Não faz sentido lembrar toda a sintaxe de todos os produtos IMO.
Na verdade, prefiro o seguinte no SQL Server 2008:
SELECT Table1.Column1, Table1.Column2, Table2.Column1, Table2.Column2, 'Some String' AS SomeString, 8 AS SomeInt
INTO Table3
FROM Table1 INNER JOIN Table2 ON Table1.Column1 = Table2.Column3
Ele elimina a etapa de adição do conjunto Insert(), e você apenas seleciona quais valores vão para a tabela.
Basta usar parênteses para SELECIONAR cláusula em INSERT.Por exemplo assim:
INSERT INTO Table1 (col1, col2, your_desired_value_from_select_clause, col3)
VALUES (
'col1_value',
'col2_value',
(SELECT col_Table2 FROM Table2 WHERE IdTable2 = 'your_satisfied_value_for_col_Table2_selected'),
'col3_value'
);
select *
into tmp
from orders
Parece bom, mas funciona apenas se o tmp não existir (cria e preenche).(servidor SQL)
Para inserir na tabela tmp existente:
set identity_insert tmp on
insert tmp
([OrderID]
,[CustomerID]
,[EmployeeID]
,[OrderDate]
,[RequiredDate]
,[ShippedDate]
,[ShipVia]
,[Freight]
,[ShipName]
,[ShipAddress]
,[ShipCity]
,[ShipRegion]
,[ShipPostalCode]
,[ShipCountry] )
select * from orders
set identity_insert tmp off
Melhor maneira de inserir vários registros de qualquer outra tabela.
INSERT INTO dbo.Users
( UserID ,
Full_Name ,
Login_Name ,
Password
)
SELECT UserID ,
Full_Name ,
Login_Name ,
Password
FROM Users_Table
(INNER JOIN / LEFT JOIN ...)
(WHERE CONDITION...)
(OTHER CLAUSE)
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT COLUMN_NAME
FROM ANOTHER_TABLE_NAME
WHERE CONDITION;
Duas abordagens para inserção com subconsulta selecionada.
- Com a subconsulta SELECT retornando resultados com Uma linha.
- Com a subconsulta SELECT retornando resultados com Várias linhas.
1.Abordagem para com a subconsulta SELECT retornando resultados com uma linha.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
VALUES ('DUMMY1', (SELECT <field> FROM <table_name> ),'DUMMY2');
Nesse caso, ele assume que a subconsulta SELECT retorna apenas uma linha de resultado com base na condição WHERE ou funções agregadas SQL como SUM, MAX, AVG etc.Caso contrário, gerará erro
2.Abordagem para com a subconsulta SELECT retornando resultados com várias linhas.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
SELECT 'DUMMY1', <field>, 'DUMMY2' FROM <table_name>;
A segunda abordagem funcionará para ambos os casos.
Se você seguir a rota INSERT VALUES para inserir várias linhas, certifique-se de delimitar os VALUES em conjuntos usando parênteses, então:
INSERT INTO `receiving_table`
(id,
first_name,
last_name)
VALUES
(1002,'Charles','Babbage'),
(1003,'George', 'Boole'),
(1001,'Donald','Chamberlin'),
(1004,'Alan','Turing'),
(1005,'My','Widenius');
Caso contrário, o MySQL objeta que "A contagem de colunas não corresponde à contagem de valores na linha 1", e você acaba escrevendo uma postagem trivial quando finalmente descobre o que fazer a respeito.