Melhor maneira de inserir inserções com várias linhas no Oracle?

262

Estou procurando uma boa maneira de executar inserções de várias linhas em um banco de dados Oracle 9. O seguinte funciona no MySQL, mas não parece ser suportado no Oracle.

INSERT INTO TMP_DIM_EXCH_RT 
(EXCH_WH_KEY, 
 EXCH_NAT_KEY, 
 EXCH_DATE, EXCH_RATE, 
 FROM_CURCY_CD, 
 TO_CURCY_CD, 
 EXCH_EFF_DATE, 
 EXCH_EFF_END_DATE, 
 EXCH_LAST_UPDATED_DATE) 
VALUES
    (1, 1, '28-AUG-2008', 109.49, 'USD', 'JPY', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
    (2, 1, '28-AUG-2008', .54, 'USD', 'GBP', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
    (3, 1, '28-AUG-2008', 1.05, 'USD', 'CAD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
    (4, 1, '28-AUG-2008', .68, 'USD', 'EUR', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
    (5, 1, '28-AUG-2008', 1.16, 'USD', 'AUD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
    (6, 1, '28-AUG-2008', 7.81, 'USD', 'HKD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008');
Jamey
fonte

Respostas:

165

Isso funciona no Oracle:

insert into pager (PAG_ID,PAG_PARENT,PAG_NAME,PAG_ACTIVE)
          select 8000,0,'Multi 8000',1 from dual
union all select 8001,0,'Multi 8001',1 from dual

O que deve ser lembrado aqui é usar a from dualdeclaração.

( fonte )

Espo
fonte
6
Há também algo chamado "Inserir tudo" a partir de 9i (?)
11/11/2010
4
Sendo exigente, mas a formatação faz mais sentido se você colocar "unir tudo" no final de cada linha de seleção (exceto a última).
Jamie
Uma desvantagem com isso é que nós não podemos usar uma sequnce.nextvalvez que é proibido em unionde select. Em vez disso, podemos prosseguir INSERT ALL.
Sql_dummy 8/17
5
@ Jamie: a formatação do Espo é um pouco mais inteligente, no sentido de que você não precisa se preocupar se está na última linha ou não, ao adicionar novas linhas. Portanto, depois de selecionar suas duas primeiras seleções, você poderá copiar / colar facilmente a última linha (ou a do meio), concentrando-se apenas nos valores que precisa alterar. É um truque comum para muitos outros casos em qualquer idioma (vírgula, operadores lógicos, mais ...). É apenas uma questão de hábito, muitas práticas anteriores foram revisadas para focar mais na responsabilidade do código do que na intuitividade.
Laurent.B
qual é o máximo para 12c?
Toolkit
363

No Oracle, para inserir várias linhas na tabela t com as colunas col1, col2 e col3, você pode usar a seguinte sintaxe:

INSERT ALL
   INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3')
   INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3')
   INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3')
   .
   .
   .
SELECT 1 FROM DUAL;
Myto
fonte
54
Eu não entendo o que SELECT 1 FROM DUALfaz.
jameshfisher
55
INSERT ALLrequer uma SELECTsubconsulta. Para contornar isso, SELECT 1 FROM DUALé usado para fornecer uma única linha de dados fictícios.
Markus Jarderot
40
Como isso difere de várias instruções de inserção? Você ainda tem a repetição nos nomes das colunas, por isso não parece ganhar muito.
precisa
28
Cerca de 10 a 12 Várias instruções INSERT são concluídas em 2 segundos no meu PC, enquanto a sintaxe acima é capaz de INSERIR 1000 registros por segundo! Impressionado! Note que EU COMPROMISSO apenas no final.
Kent Pawar
13
Isso funciona bem, no entanto, se você estiver inserindo usando uma sequência, diga user.NEXTVAL, ele retornará o mesmo valor para cada inserção. Você pode incrementá-lo manualmente na inserção de todas e atualizar a sequência fora da inserção.
user1412523
33

Use o SQL * Loader. É preciso um pouco de configuração, mas se isso não acontecer, vale a pena.

Criar a tabela

SQL> create table ldr_test (id number(10) primary key, description varchar2(20));
Table created.
SQL>

Criar CSV

oracle-2% cat ldr_test.csv
1,Apple
2,Orange
3,Pear
oracle-2% 

Criar arquivo de controle do carregador

oracle-2% cat ldr_test.ctl 
load data

 infile 'ldr_test.csv'
 into table ldr_test
 fields terminated by "," optionally enclosed by '"'              
 ( id, description )

oracle-2% 

Execute o comando SQL * Loader

oracle-2% sqlldr <username> control=ldr_test.ctl
Password:

SQL*Loader: Release 9.2.0.5.0 - Production on Wed Sep 3 12:26:46 2008

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Commit point reached - logical record count 3

Confirmar inserção

SQL> select * from ldr_test;

        ID DESCRIPTION
---------- --------------------
         1 Apple
         2 Orange
         3 Pear

SQL>

O SQL * Loader tem muitas opções e pode receber praticamente qualquer arquivo de texto como entrada. Você pode até alinhar os dados em seu arquivo de controle, se desejar.

Aqui está uma página com mais alguns detalhes -> SQL * Loader

Matthew Watson
fonte
Este deve ser o IMHO resposta superior, qualquer outra coisa (para tarefas de grande porte) está pedindo para ter problemas
roblogic
A coluna ID na minha tabela é gerada automaticamente. Posso simplesmente pular o campo ID no arquivo de controle do carregador?
Thom DeCarlo
@Thom, por exemplo, utilizar o sequence.nextval fruit_id "fruit_seq.nextval"na definição de coluna
roblogic
50 milhões de registros em poucos minutos. Caminho a percorrer
Toolkit
20

Sempre que preciso fazer isso, construo um bloco PL / SQL simples com um procedimento local como este:

declare
   procedure ins
   is
      (p_exch_wh_key INTEGER, 
       p_exch_nat_key INTEGER, 
       p_exch_date DATE, exch_rate NUMBER, 
       p_from_curcy_cd VARCHAR2, 
       p_to_curcy_cd VARCHAR2, 
       p_exch_eff_date DATE, 
       p_exch_eff_end_date DATE, 
       p_exch_last_updated_date DATE);
   begin
      insert into tmp_dim_exch_rt 
      (exch_wh_key, 
       exch_nat_key, 
       exch_date, exch_rate, 
       from_curcy_cd, 
       to_curcy_cd, 
       exch_eff_date, 
       exch_eff_end_date, 
       exch_last_updated_date) 
      values
      (p_exch_wh_key, 
       p_exch_nat_key, 
       p_exch_date, exch_rate, 
       p_from_curcy_cd, 
       p_to_curcy_cd, 
       p_exch_eff_date, 
       p_exch_eff_end_date, 
       p_exch_last_updated_date);
   end;
begin
   ins (1, 1, '28-AUG-2008', 109.49, 'USD', 'JPY', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
   ins (2, 1, '28-AUG-2008', .54, 'USD', 'GBP', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
   ins (3, 1, '28-AUG-2008', 1.05, 'USD', 'CAD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
   ins (4, 1, '28-AUG-2008', .68, 'USD', 'EUR', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
   ins (5, 1, '28-AUG-2008', 1.16, 'USD', 'AUD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008'),
   ins (6, 1, '28-AUG-2008', 7.81, 'USD', 'HKD', '28-AUG-2008', '28-AUG-2008', '28-AUG-2008');
end;
/

fonte
12

Se você já possui os valores que deseja inserir em outra tabela, poderá inserir a partir de uma instrução select.

INSERT INTO a_table (column_a, column_b) SELECT column_a, column_b FROM b_table;

Caso contrário, você pode listar várias instruções de inserção de linha única e enviar várias consultas em massa para economizar tempo para algo que funcione no Oracle e no MySQL.

A solução da @Espo também é boa que funcionará no Oracle e no MySQL se seus dados ainda não estiverem em uma tabela.

Ryan Ahearn
fonte
4

você pode inserir loop usando se desejar inserir alguns valores aleatórios.

BEGIN 
    FOR x IN 1 .. 1000 LOOP
         INSERT INTO MULTI_INSERT_DEMO (ID, NAME)
         SELECT x, 'anyName' FROM dual;
    END LOOP;
END;
Girdhar Singh Rathore
fonte
0

Aqui está uma orientação passo a passo muito útil para inserir várias linhas no Oracle:

https://livesql.oracle.com/apex/livesql/file/content_BM1LJQ87M5CNIOKPOWPV6ZGR3.html

O último passo:

INSERT ALL
/* Everyone is a person, so insert all rows into people */
WHEN 1=1 THEN
INTO people (person_id, given_name, family_name, title)
VALUES (id, given_name, family_name, title)
/* Only people with an admission date are patients */
WHEN admission_date IS NOT NULL THEN
INTO patients (patient_id, last_admission_date)
VALUES (id, admission_date)
/* Only people with a hired date are staff */
WHEN hired_date IS NOT NULL THEN
INTO staff (staff_id, hired_date)
VALUES (id, hired_date)
  WITH names AS (
    SELECT 4 id, 'Ruth' given_name, 'Fox' family_name, 'Mrs' title,
           NULL hired_date, DATE'2009-12-31' admission_date
    FROM   dual UNION ALL
    SELECT 5 id, 'Isabelle' given_name, 'Squirrel' family_name, 'Miss' title ,
           NULL hired_date, DATE'2014-01-01' admission_date
    FROM   dual UNION ALL
    SELECT 6 id, 'Justin' given_name, 'Frog' family_name, 'Master' title,
           NULL hired_date, DATE'2015-04-22' admission_date
    FROM   dual UNION ALL
    SELECT 7 id, 'Lisa' given_name, 'Owl' family_name, 'Dr' title,
           DATE'2015-01-01' hired_date, NULL admission_date
    FROM   dual
  )
  SELECT * FROM names
akasha
fonte
0

No meu caso, consegui usar uma instrução de inserção simples para inserir em massa muitas linhas em TABLE_A usando apenas uma coluna de TABLE_B e obtendo os outros dados em outro lugar (sequência e um valor codificado):

INSERT INTO table_a (
    id,
    column_a,
    column_b
)
    SELECT
        table_a_seq.NEXTVAL,
        b.name,
        123
    FROM
        table_b b;

Resultado:

ID: NAME: CODE:
1, JOHN, 123
2, SAM, 123
3, JESS, 123

etc

java-addict301
fonte