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');

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 )


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;

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 *


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

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.


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;


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

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.