Я ищу хороший способ выполнить многострочную вставку в базу данных 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');


Это работает в 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.
Будучи разборчивым, форматирование имеет больше смысла, если вы помещаете «объединение всех» в конец каждой строки выбора (кроме последней).
Одним из недостатков этого является то, что мы не можем использовать sequnce.nextval, поскольку это запрещено в union или select. Вместо этого мы можем использовать INSERT ALL.
@Jamie: форматирование Espo немного умнее в том смысле, что вам не нужно беспокоиться о том, находитесь ли вы на последней строке или нет, при добавлении новых строк. Следовательно, как только у вас есть 2 первых выбора, вы можете легко скопировать / вставить последнюю строку (или среднюю), сосредоточившись только на значениях, которые вам нужно изменить. Это обычная уловка для множества других случаев на любых языках (запятая, логические операторы и т. д.). Это просто дело привычки, многие прежние практики были пересмотрены, чтобы сосредоточиться на ответственности кода больше, чем на интуитивности.
какой максимум для 12с?
Как это точно отвечает на вопрос? Что такое from dual и куда вставляются фактические данные?
Что делать, если мне нужно вставить следующее значение из последовательности (sequence.nextval)? Я получаю эту ошибку 02287. 00000 - «Порядковый номер здесь не разрешен» * Причина: Указанный порядковый номер (CURRVAL или NEXTVAL) не подходит здесь в операторе.
ссылка на источник недоступна
Интересно, какой метод быстрее - с использованием select и union или INSERT ALL? Оба варианта кажутся излишними для частой задачи вставки множества строк в одну и ту же таблицу. MySql принял хорошее решение, предоставив для него заданный синтаксис.
Если у вас есть значения, которые вы хотите вставить в другую таблицу, вы можете вставить их из оператора выбора.
INSERT INTO a_table (column_a, column_b) SELECT column_a, column_b FROM b_table;
В противном случае вы можете перечислить группу операторов вставки одной строки и отправить несколько запросов сразу, чтобы сэкономить время для чего-то, что работает как в Oracle, так и в MySQL.
Решение @Espo также является хорошим решением, которое будет работать как в Oracle, так и в MySQL, если ваших данных еще нет в таблице.
Используйте 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 * Loader имеет множество опций и может принимать практически любой текстовый файл в качестве входных данных. Вы даже можете встроить данные в свой контрольный файл, если хотите.
Вот страница с более подробной информацией -> Загрузчик SQL *
Это должен быть главный ответ ИМХО, все остальное (для крупномасштабных задач) вызывает проблемы
Столбец ID в моей таблице создается автоматически. Могу я просто пропустить поле ID в файле управления загрузчиком?
@Thom, используйте sequence.nextval, например fruit_id "fruit_seq.nextval" в определении столбца
50 миллионов записей за несколько минут. Путь к выходу
Когда мне нужно это сделать, я создаю простой блок 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;
/
В 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;
Я не понимаю, что делает SELECT 1 FROM DUAL.
Согласно эта страница руководства, SELECT * FROM DUAL тоже работает.
@jameshfisher Я не знаю, почему для множественной вставки требуется выбор из DUAL, но я могу сказать вам, что такое DUAL: предопределенная таблица. Запустите SELECT * FROM DUAL, чтобы просмотреть его.
INSERT ALL требует подзапроса SELECT. Чтобы обойти это, SELECT 1 FROM DUAL используется для выдачи одной строки фиктивных данных.
Чем это отличается от нескольких операторов вставки? У вас все еще есть повторения в именах столбцов, поэтому, похоже, не так много.
Около 10-12 нескольких операторов INSERT выполняются на моем ПК за 2 секунды, в то время как приведенный выше синтаксис позволяет INSERT 1000 записей в секунду! Впечатленный! Обратите внимание, что Я ПРИНИМАЮСЬ только в конце.
Это отлично работает, однако, если вы вставляете с использованием последовательности, скажем, user.NEXTVAL, она вернет одно и то же значение для каждой вставки. Вы можете вручную увеличить его во вставке всего, а затем обновить последовательность вне вставки.
@ user1412523 - вот почему у вас должен быть триггер ON INSERT...FOR EACH ROW в таблице, чтобы получать значения из вашей последовательности и назначать их столбцу первичного ключа в каждой вставленной строке. Кроме того, это означает, что код приложения не должен знать, какую последовательность использовать и т. д.
Будет ли это оптимальным / оптимизированным способом одновременной вставки 40 тыс. Записей?
По сравнению с версией, опубликованной Espo, это значительно медленнее. этот подход обошелся мне примерно в 2 минуты на 900 строк, в то время как он стоит секунды.
См. Здесь подробное объяснение ограничений NEXTVAL stackoverflow.com/questions/28523262/multiple-insert-sql-ora cle
Просто хотел поделиться тем, что из-за такого рода идиосинкразии и несоответствия стандартам (SQL-92) меня действительно озадачивает, почему Oracle по-прежнему выбирается в качестве базы данных.
Отличный ответ и просто сделал мою жизнь намного проще (перевод сотен строк Excel в оператор вставки). Просто помните, что, хотя это выглядит неправильно для MySQL и исходного вопроса, как правильно показал @Myto в Oracle, между предложениями 'into' нет запятых.
Курсоры также можно использовать, но это неэффективно. В следующем сообщении stackoverflow обсуждается использование курсоров:
вы можете вставить цикл using, если хотите вставить случайные значения.
BEGIN
FOR x IN 1 .. 1000 LOOP
INSERT INTO MULTI_INSERT_DEMO (ID, NAME)
SELECT x, 'anyName' FROM dual;
END LOOP;
END;
Вот очень полезное пошаговое руководство по вставке нескольких строк в 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
В моем случае я смог использовать простой оператор вставки для массовой вставки множества строк в 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
так далее
Еще в 9i (?) Есть что-то под названием "Вставить все".