Cara terbaik untuk melakukan multi-row insert di Oracle?

262

Saya mencari cara yang baik untuk melakukan insert multi-baris ke dalam database Oracle 9. Berikut ini berfungsi di MySQL tetapi tampaknya tidak didukung di 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
sumber

Jawaban:

165

Ini berfungsi di 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

Yang perlu diingat di sini adalah menggunakan from dualpernyataan itu.

( sumber )

Espo
sumber
6
Ada juga sesuatu yang disebut "Masukkan Semua" pada 9i (?)
mlathe
4
Menjadi pemilih, tetapi pemformatan lebih masuk akal jika Anda meletakkan "gabungan semua" di akhir setiap baris pilihan (kecuali untuk yang terakhir).
Jamie
Salah satu kelemahan dengan ini kami tidak bisa menggunakan sequnce.nextvalseperti yang dilarang di uniondari select. Sebaliknya kita bisa ikut INSERT ALL.
sql_dummy
5
@Jamie: format Espo sedikit lebih pintar dalam arti bahwa Anda tidak perlu khawatir tentang apakah Anda berada di baris terakhir atau tidak, ketika menambahkan baris baru. Oleh karena itu, setelah Anda memiliki 2 pilihan pertama, Anda dapat dengan mudah menyalin / menempelkan baris terakhir (atau yang tengah), hanya berfokus pada nilai-nilai yang harus Anda ubah. Ini adalah trik umum untuk banyak kasus lain dalam bahasa apa pun (koma, operator logika, plus ...). Ini hanya masalah kebiasaan, banyak praktik sebelumnya telah direvisi untuk fokus pada pertanggungjawaban kode lebih dari sekedar intuitif.
Laurent.B
Berapa maksimum untuk 12c?
Toolkit
363

Di Oracle, untuk menyisipkan banyak baris ke tabel t dengan kolom col1, col2 dan col3 Anda dapat menggunakan sintaks berikut:

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
sumber
54
Saya tidak mengerti apa yang SELECT 1 FROM DUALterjadi.
jameshfisher
55
INSERT ALLmembutuhkan SELECTsubquery. Untuk menyiasatinya, SELECT 1 FROM DUALdigunakan untuk memberikan satu baris data dummy.
Markus Jarderot
40
Apa bedanya dengan banyak pernyataan sisipan? Anda masih memiliki pengulangan pada nama kolom jadi sepertinya tidak mendapatkan banyak.
Burhan Ali
28
Sekitar 10-12 Beberapa pernyataan INSERT diselesaikan dalam 2secs di PC saya, sementara sintaks di atas dapat INSERT 1000 catatan per detik! Terkesan! Perhatikan bahwa saya BERKOMITMEN hanya di akhir.
Kent Pawar
13
Ini berfungsi dengan baik, namun jika Anda memasukkan menggunakan urutan, katakan pengguna. NEXTVAL itu akan mengembalikan nilai yang sama untuk setiap memasukkan. Anda bisa menambahkannya secara manual di semua sisipan, lalu memperbarui urutan di luar sisipan.
user1412523
33

Gunakan SQL * Loader. Dibutuhkan sedikit pengaturan, tetapi jika ini bukan salah satu, nilainya.

Buat tabel

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

Buat CSV

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

Buat File Kontrol Pemuat

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% 

Jalankan perintah 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

Konfirmasikan penyisipan

SQL> select * from ldr_test;

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

SQL>

SQL * Loader memiliki banyak opsi, dan dapat mengambil hampir semua file teks sebagai inputnya. Anda bahkan dapat memasukkan data dalam file kontrol Anda jika diinginkan.

Berikut ini adalah halaman dengan beberapa rincian lebih lanjut -> SQL * Loader

Matthew Watson
sumber
Ini harus menjadi jawaban teratas IMHO, hal lain (untuk tugas skala besar) meminta masalah
roblogic
Kolom ID di tabel saya dibuat secara otomatis. Bisakah saya melewatkan bidang ID di file kontrol loader?
Thom DeCarlo
@Thom, gunakan misalnya sequence.nextval fruit_id "fruit_seq.nextval"dalam definisi kolom
roblogic
50 juta catatan dalam beberapa menit. Way to go
Toolkit
20

Setiap kali saya perlu melakukan ini saya membangun blok PL / SQL sederhana dengan prosedur lokal seperti ini:

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

sumber
12

Jika Anda memiliki nilai yang ingin Anda sisipkan di tabel lain, maka Anda bisa menyisipkan dari pernyataan pilih.

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

Jika tidak, Anda bisa daftar sekelompok pernyataan menyisipkan baris tunggal dan mengirimkan beberapa permintaan secara massal untuk menghemat waktu untuk sesuatu yang berfungsi baik di Oracle dan MySQL.

Solusi @Espo juga bagus untuk Oracle dan MySQL jika data Anda belum ada dalam tabel.

Ryan Ahearn
sumber
4

Anda bisa memasukkan menggunakan loop jika Anda ingin memasukkan beberapa nilai acak.

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
sumber
0

Berikut ini adalah panduan langkah demi langkah yang sangat berguna untuk memasukkan banyak baris di Oracle:

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

Langkah terakhir:

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
sumber
0

Dalam kasus saya, saya dapat menggunakan pernyataan penyisipan sederhana untuk menyisipkan banyak baris ke TABLE_A secara massal menggunakan hanya satu kolom dari TABLE_B dan mendapatkan data lain di tempat lain (urutan dan nilai hardcoded):

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

Hasil:

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

dll

java-addict301
sumber