Najlepszy sposób na wstawianie wielu wierszy w Oracle?

262

Szukam dobrego sposobu wykonywania wstawień wielorzędowych w bazie danych Oracle 9. Poniższe działa w MySQL, ale nie wydaje się być obsługiwane w 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
źródło

Odpowiedzi:

165

Działa to w 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

Należy tutaj pamiętać o użyciu from dualinstrukcji.

( źródło )

Espo
źródło
6
Jest też coś o nazwie „Insert All” od 9i (?)
zgodnie z
4
Bycie wybrednym, ale formatowanie jest bardziej sensowne, jeśli umieścisz „zjednoczenie wszystkich” na końcu każdej linii wyboru (z wyjątkiem ostatniej).
Jamie,
Jedną z wad jest to nie możemy używać sequnce.nextvaljak to jest zakazane unionod select. Zamiast tego możemy iść z INSERT ALL.
sql_dummy
5
@Jamie: formatowanie Espo jest nieco mądrzejsze w tym sensie, że nie musisz się martwić, czy jesteś w ostatniej linii, czy nie, dodając nowe linie. Dlatego, gdy masz już 2 pierwsze wybory, możesz łatwo skopiować / wkleić ostatni wiersz (lub środkowy), koncentrując się tylko na wartościach, które musisz zmienić. Jest to powszechna sztuczka w wielu innych przypadkach w dowolnym języku (przecinek, operatory logiczne oraz ...). To tylko kwestia przyzwyczajenia, wiele wcześniejszych praktyk zostało zmienionych, aby bardziej skupiać się na odpowiedzialności za kod niż na intuicyjności.
Laurent.B
jaka jest maksymalna wartość dla 12c?
Zestaw narzędzi
362

W Oracle, aby wstawić wiele wierszy do tabeli t za pomocą kolumn col1, col2 i col3, można użyć następującej składni:

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
źródło
54
Nie rozumiem co SELECT 1 FROM DUALrobi.
jameshfisher
55
INSERT ALLwymaga SELECTpodzapytania. Aby obejść ten problem, SELECT 1 FROM DUALsłuży do podania jednego wiersza fałszywych danych.
Markus Jarderot,
40
Czym różni się to od wielu instrukcji wstawiania? Nadal masz powtarzanie w nazwach kolumn, więc wydaje się, że nie zyskujesz dużo.
Burhan Ali
28
Na moim komputerze wykonuje się około 10-12 instrukcji INSERT w 2 sek., A powyższa składnia umożliwia INSERT 1000 rekordów na sekundę! Pod wrażeniem! Zauważ, że ZGADZAM SIĘ tylko na końcu.
Kent Pawar
13
Działa to dobrze, jednak jeśli wstawiasz za pomocą sekwencji, powiedz user.NEXTVAL, zwróci tę samą wartość dla każdej wstawki. Możesz ręcznie zwiększyć go we wstawce wszystkie, a następnie zaktualizować sekwencję poza wstawką.
user1412523,
33

Użyj programu ładującego SQL *. To wymaga trochę konfiguracji, ale jeśli nie jest to jednorazowe, warto.

Utwórz tabelę

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

Utwórz CSV

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

Utwórz plik kontrolny modułu ładującego

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% 

Uruchom komendę 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

Potwierdź wstawienie

SQL> select * from ldr_test;

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

SQL>

Program SQL * Loader ma wiele opcji i może przyjąć prawie dowolny plik tekstowy jako dane wejściowe. Możesz nawet wstawić dane do pliku kontrolnego, jeśli chcesz.

Oto strona z kilkoma szczegółami -> Moduł ładujący SQL *

Matthew Watson
źródło
To powinna być najwyższa odpowiedź IMHO, wszystko inne (do zadań na dużą skalę) wymaga kłopotów
roblogic
Kolumna ID w mojej tabeli jest generowana automatycznie. Czy mogę po prostu pominąć pole ID w pliku kontrolnym modułu ładującego?
Thom DeCarlo,
@Tom, użyj sekwencji.nextval np. fruit_id "fruit_seq.nextval"W definicji kolumny
roblogic
50 milionów rekordów w kilka minut. Droga
Toolkit
20

Ilekroć muszę to zrobić, buduję prosty blok PL / SQL za pomocą lokalnej procedury takiej jak ta:

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

źródło
12

Jeśli masz już wartości, które chcesz wstawić do innej tabeli, możesz wstawić z instrukcji select.

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

W przeciwnym razie możesz wymienić kilka instrukcji wstawiania w jednym wierszu i przesłać zbiorczo kilka zapytań, aby zaoszczędzić czas na coś, co działa zarówno w Oracle, jak i MySQL.

Rozwiązanie @Espo jest również dobrym rozwiązaniem, które będzie działać zarówno w Oracle, jak i MySQL, jeśli danych nie ma jeszcze w tabeli.

Ryan Ahearn
źródło
4

możesz wstawić za pomocą pętli, jeśli chcesz wstawić losowe wartości.

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
źródło
0

Oto bardzo przydatna wskazówka krok po kroku dotycząca wstawiania wielu wierszy w Oracle:

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

Ostatni krok:

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
źródło
0

W moim przypadku byłem w stanie użyć prostej instrukcji insert, aby zbiorczo wstawić wiele wierszy do TABELI_A, używając tylko jednej kolumny z TABELI_B i uzyskać inne dane w innym miejscu (sekwencja i wartość zakodowana na stałe):

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

Wynik:

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

itp

java-addict301
źródło