Il modo migliore per eseguire l'inserimento di più righe in Oracle?


262

Sto cercando un buon modo per eseguire inserimenti su più righe in un database Oracle 9. Quanto segue funziona in MySQL ma non sembra essere supportato in 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');

Risposte:


165

Questo funziona in 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

La cosa da ricordare qui è usare la from dualdichiarazione.

( fonte )


6
C'è anche qualcosa chiamato "Inserisci tutto" a partire dal 9i (?)
ml

4
Essere pignoli, ma la formattazione ha più senso se metti "unisci tutto" alla fine di ogni riga selezionata (tranne l'ultima).
Jamie,

Uno svantaggio di questo è non possiamo usare un sequnce.nextvaldato che è vietato in unionsu select. Invece possiamo andare con INSERT ALL.
sql_dummy

5
@Jamie: la formattazione di Espo è leggermente più intelligente, nel senso che non devi preoccuparti se sei sull'ultima riga o meno, quando aggiungi nuove righe. Quindi, una volta che hai le tue prime 2 selezioni, puoi facilmente copiare / incollare l'ultima riga (o una riga centrale), concentrandoti solo sui valori che devi cambiare. È un trucco comune per molti altri casi in qualsiasi lingua (virgola, operatori logici, oltre ...). È solo una questione di abitudine, molte pratiche precedenti sono state riviste per concentrarsi sulla responsabilità del codice più che sull'intuitività.
Laurent.B,

qual è il massimo per 12c?
Toolkit,

363

In Oracle, per inserire più righe nella tabella t con le colonne col1, col2 e col3 è possibile utilizzare la sintassi seguente:

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;

54
Non capisco cosa SELECT 1 FROM DUALfa.
jameshfisher,

55
INSERT ALLrichiede una SELECTsottoquery. Per aggirare ciò, SELECT 1 FROM DUALviene utilizzato per fornire una singola riga di dati fittizi.
Markus Jarderot,

40
In che cosa differisce da più istruzioni insert? Hai ancora la ripetizione sui nomi delle colonne, quindi non sembra guadagnare molto.
Burhan Ali,

28
Circa 10-12 istruzioni INSERT multiple vengono completate in 2 secondi sul mio PC, mentre la sintassi sopra è in grado di INSERIRE 1000 record al secondo! Colpito! Si noti che COMMIT solo alla fine.
Kent Pawar,

13
Funziona bene, tuttavia se si sta inserendo usando una sequenza, dire user.NEXTVAL restituirà lo stesso valore per ogni inserimento. È possibile incrementarlo manualmente nell'insert all, quindi aggiornare la sequenza all'esterno dell'insert.
user1412523

33

Usa SQL * Loader. Ci vuole un po 'di installazione, ma se questo non è unico, ne vale la pena.

Crea tabella

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

Crea CSV

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

Crea file di controllo caricatore

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% 

Esegui il 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

Conferma l'inserimento

SQL> select * from ldr_test;

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

SQL>

SQL * Loader ha molte opzioni e può prendere praticamente qualsiasi file di testo come input. Puoi anche incorporare i dati nel tuo file di controllo, se lo desideri.

Ecco una pagina con alcuni dettagli -> Caricatore SQL *


Questa dovrebbe essere la risposta principale IMHO, qualsiasi altra cosa (per compiti su larga scala) sta chiedendo problemi
roblogic

La colonna ID nella mia tabella è generata automaticamente. Posso semplicemente saltare il campo ID nel file di controllo del caricatore?
Thom DeCarlo,

@Thom, usa la sequenza.nextval ad es. fruit_id "fruit_seq.nextval"Nella definizione della colonna
roblogic

50 milioni di dischi in pochi minuti. Ben fatto
Toolkit,

20

Ogni volta che devo fare questo, costruisco un semplice blocco PL / SQL con una procedura locale come questa:

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;
/

12

Se disponi già dei valori che desideri inserire in un'altra tabella, puoi inserire da un'istruzione select.

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

Altrimenti, puoi elencare un mucchio di istruzioni di inserimento a riga singola e inviare diverse query in blocco per risparmiare tempo per qualcosa che funziona sia in Oracle che in MySQL.

La soluzione di @Espo è anche una buona soluzione che funzionerà sia in Oracle che in MySQL se i tuoi dati non sono già in una tabella.


4

puoi inserire usando il ciclo se vuoi inserire alcuni valori casuali.

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


0

Ecco una guida passo passo molto utile per inserire più righe in Oracle:

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

L'ultimo 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

0

Nel mio caso, sono stato in grado di utilizzare una semplice istruzione insert per inserire in blocco molte righe in TABLE_A usando solo una colonna da TABLE_B e ottenendo gli altri dati altrove (sequenza e un valore codificato):

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

Risultato:

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

eccetera

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.