Найкращий спосіб зробити багаторядкові вставки в Oracle?


262

Я шукаю хороший спосіб виконати багаторядкові вставки в базу даних Oracle 9. Наступні роботи в MySQL, але, схоже, не підтримуються в 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');

Відповіді:


165

Це працює в 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

Тут слід пам’ятати - використовувати from dualвислів.

( джерело )


6
Існує також щось, що називається "Вставити все" станом на 9i (?)
mlathe

4
Будучи вибагливим, але форматування має більше сенсу, якщо ви ставите "об'єднати всіх" в кінці кожного рядка вибору (крім останнього).
Джеймі

Одним з недоліків цього ми не можемо використовувати , sequnce.nextvalяк це заборонено в unionпро select. Замість цього ми можемо піти INSERT ALL.
sql_dummy

5
@Jamie: форматування Espo трохи розумніше в тому сенсі, що вам не доведеться турбуватися про те, перебуваєте ви на останньому рядку чи ні, додаючи нові рядки. Отже, після того, як у вас є два перших вибору, ви можете легко скопіювати / вставити останній рядок (або середній), орієнтуючись лише на значення, які вам доведеться змінити. Це загальна хитрість для безлічі інших випадків на будь-яких мовах (кома, логічні оператори, плюс…). Це лише питання звички, багато колишніх практик були переглянуті, щоб зосередити увагу на відповідальності кодексу більше, ніж на інтуїтивності.
Лоран.Бай

який максимум для 12c?
Інструментарій

362

В Oracle, щоб вставити кілька рядків у таблицю t зі стовпцями col1, col2 та col3, ви можете використовувати наступний синтаксис:

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
Я не розумію, що SELECT 1 FROM DUALробить.
jameshfisher

55
INSERT ALLвимагає SELECTпідпиту. Щоб обійти це, SELECT 1 FROM DUALвикористовується для надання єдиного ряду фіктивних даних.
Маркус Джардеро

40
Чим це відрізняється від кількох операторів вставки? У вас все ще є повторення у назвах стовпців, тому, схоже, не надто багато.
Бурхан Алі

28
Близько 10-12 декількох операторів INSERT завершуються за два секунди на моєму ПК, тоді як вищевказаний синтаксис може ВСТАВИТИ 1000 записів за секунду! Вражений! Зауважте, що Я ВІДПОВІДАЮТЕ лише наприкінці.
Кент Павар

13
Це добре працює, проте якщо ви вставляєте за допомогою послідовності, скажіть, користувач. NEXTVAL він поверне однакове значення для кожної вставки. Ви можете вручну збільшити його у вставці все, а потім оновити послідовність поза вставкою.
користувач1412523

33

Використовуйте SQL * Loader. Потрібно трохи налаштувати, але якщо це не одноразово, воно того варте.

Створити таблицю

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

Створіть CSV

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

Створіть файл управління завантажувачем

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% 

Запустіть команду 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

Підтвердити вставку

SQL> select * from ldr_test;

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

SQL>

SQL * Навантажувач має безліч варіантів, і він може брати майже будь-який текстовий файл як свій вхід. Ви навіть можете вбудовувати дані у свій керуючий файл, якщо хочете.

Ось сторінка з додатковими деталями -> SQL * Loader


Це має бути головна відповідь ІМХО, все інше (для великих масштабних завдань) задає проблеми
roblogic

Стовпчик ідентифікаторів у моїй таблиці автоматично генерується. Чи можу я просто пропустити поле ідентифікатора у файлі управління завантажувачем?
Thom DeCarlo

@Thom, використовуйте послідовність.nextval, наприклад, fruit_id "fruit_seq.nextval"у визначенні стовпця
roblogic

50 мільйонів записів за кілька хвилин. Шлях
Інструментарій

20

Щоразу, коли мені потрібно це зробити, я будую простий блок PL / SQL з локальною процедурою, як це:

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

Якщо у вас вже є значення, які ви хочете вставити в іншу таблицю, тоді ви можете вставити з оператора select.

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

В іншому випадку ви можете перерахувати купу заяв про вставлення в один рядок і надіслати кілька запитів оптом, щоб заощадити час на те, що працює як в Oracle, так і в MySQL.

Рішення @Espo також добре, що буде працювати як в Oracle, так і в MySQL, якщо ваші дані ще не є в таблиці.


4

ви можете вставити за допомогою циклу, якщо ви хочете вставити деякі випадкові значення.

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


0

Ось дуже корисна покрокова інструкція для вставки кількох рядків в Oracle:

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

Останній крок:

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

У моєму випадку мені вдалося використати просту операцію вставки для масового вставки багатьох рядків у TABLE_A, використовуючи лише один стовпець з TABLE_B, а інші дані отримувати в іншому місці (послідовність та значення, що твердо кодується):

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

Результат:

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

тощо

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.