Слияние данных (MERGE)
Функция
Определение оператора слияния (синхронизации) приемника и источника данных.
В некоторых информационных системах встречается потребность в передаче строк из таблицы, созданной или обновленной при выполнении транзакции (транзакционной или исходной таблицы), в некоторую основную (целевую) таблицу БД. Исходная таблица может содержать как обновленные варианты строк, существующие в целевой таблице, так и новые строки, которые должны быть добавлены в целевую таблицу.
С помощью традиционных операторов манипулирования данными содержимое исходной таблицы можно перенести в целевую таблицу за два шага:
-
выполнить оператор
UPDATEдля всех строк целевой таблицы, для которых имеются модифицированные «двойники» в исходной таблице; -
выполнить оператор
INSERTдля добавления в целевую таблицу тех строк исходной таблицы, для которых в целевой таблице нет «двойников».
Оператор MERGE реализует эти функции за один шаг.
Спецификация
::=USING [имя схемы.]исходная таблица [[AS] псевдоним таблицы]
ON условие слияния спецификация слияния
::=::=::=::=::=::={значимое выражение
|подзапрос
|DEFAULT
|NULL
|EXTFILE(NULL | ? |спецификация файла[, имя фильтра])}
::=::=::=::=::=Синтаксические правила
-
<RAL>,<WAL>– уровни доступа на чтение и запись (см. документ «Администрирование комплекса средств защиты данных», раздел «Уровни доступа»).Примечание
Поддерживается только в СУБД ЛИНТЕР БАСТИОН.
-
<Целевая таблица>– имя объекта БД (базовая таблица или обновляемое представление), который должен быть синхронизирован с<исходной таблицей>по заданному<условию слияния>. -
<Целевая таблица>не может быть удаленной таблицей, таблицей «в памяти», временной таблицей, циклической таблицей или реплицируемой таблицей. -
<Псевдоним>задает альтернативное имя, используемое для указания ссылок на целевую или исходную таблицу. -
<Исходная таблица>– имя объекта БД (базовая/временная/глобальная/удаленная таблица (за исключением циклической), подзапрос, любое представление), который является источником данных для синхронизации (слияния) с<целевой таблицей>. -
Оператор
MERGEможет иметь только одну конструкцию<слияние с сопоставлением>. -
Оператор
MERGEможет иметь только одну конструкцию<слияние без сопоставления>. -
Должно быть указано либо
<слияние сопоставление>, либо<слияние без сопоставления>, либо обе конструкции одновременно (в любом порядке). -
<Значимое выражение>может включать в себя имена столбцов как исходной, так и целевой таблицы.
Общие правила
-
Выполнение
MERGEтребует привилегииUPDATEна обновляемую таблицу при наличии конструкцииWHEN MATСHEDи привилегииINSERTна обновляемую таблицу при наличии конструкцииWHEN NOT MATСHED, а также привилегииSELECTна все используемые таблицы. -
Алгоритм выполнения оператора.
Пусть
T1–<исходная таблица>, аT2–<целевая таблица>Тогда алгоритм выполнения оператора определяется следующим образом:
-
строки таблицы
T1просматриваются в некотором порядке. ПустьR1– очередная строкаT1. Для этой строки вычисляется<условие слияния>например, синхронизация заказов на определенную датуT1.<N_заказа>=T2.<N_заказа> AND T2.<дата>='28.04.2010';
-
если значением
<условия слияния>являетсяTRUE, то есть в<целевой таблице>есть строка с данным номером заказа за указанную дату, то:-
если в операторе содержится раздел
<слияние с сопоставлением>:-
в этой строке корректируются значения тех столбцов, которые указаны в
<списке столбцов>раздела<корректировка строки>(например, вносятся сведения об изменении заказа). В<списке столбцов>указываются имена столбцов таблицыT1, т.е. что строкаR2будет модифицироваться на основе значений столбцов строкиR1; -
в противном случае строка
R1игнорируется;
-
-
-
если значением
<условия слияния>являетсяFALSE, то есть в<целевой таблице>нет строки с данным номером заказа на указанную дату, то:-
если в операторе содержится раздел
<слияние без сопоставления>:-
в таблицу
T2вставляется строка, специфицируемая списком выражений раздела<вставка строки>. В<списке столбцов>указываются имена столбцов таблицыT1, т.е. строка, заново вставляемая в таблицуT2, будет формироваться на основе значений столбцов строкиR1); -
в противном случае строка
R1игнорируется.
-
-
-
-
Для заданного
<условия слияния>каждой строке таблицыT1должна соответствовать не более чем одна строка таблицыT2. В противном случае генерируется код завершения 76 («Получено результирующее множество из нескольких записей (ожидалась одна запись)»). Таким образом, на одну строку<исходной таблицы>допускается только одна операция вставки или обновления. -
<Условие слияния>определяет критерии совпадения строк целевой и исходной таблиц. Задается с помощью конструкции<логическое выражение>.Пусть исходная таблица содержит список автовладельцев, заменивших свой автомобиль и его цвет в течение
1970года. Необходимо внести соответствующие изменения в таблицуAUTO. create or replace table upgrade_auto (id int, mod_auto char (20), color char (10)); insert into upgrade_auto (id, mod_auto, color) values (10, 'FORD', 'BLACK'); insert into upgrade_auto (id, mod_auto, color) values (5000, 'MASDA', 'RED'); MERGE INTO AUTO USING upgrade_auto as src ON (auto.personid=src.id and auto.year=70) WHEN MATCHED THEN UPDATE SET auto.model=src.mod_auto, auto.color=src.color; -
В случае указания
<слияния с сопоставлением>выполняется корректировка значениями из<исходной таблицы>всех строк<целевой таблицы>, которые удовлетворяют<условию слияния>. -
Обновляемые столбцы в
<целевой таблице>не должны быть автогенерируемыми столбцами (последовательностями, autoinc, autoinc range и т.п.). -
Если при добавлении строк
<исходная таблица>содержит значения для вставки в автогенерируемые столбцы<целевой таблицы>, то фиксируется ошибочный код завершения, точно так же, как и при выполнении соответствующегоINSERT. Чтобы избежать этого, можно, как и дляINSERT, либо вообще не задавать явно значения автогенерируемых столбцов, либо задавать такие значения, которые не вызовут этих проблем (большие максимального добавлявшегося значенияAUTOINC, не попадающие в диапазоныAUTOINC RANGEи т.п.). -
<Корректировка строки>задает список имен столбцов<целевой таблицы>, которые должны быть обновлены, и значений, которые необходимо использовать для их обновления.Обновить список автовладельцев, которые в порядке обмена старых авто на новые заменили свои автомобили. Таблица
upgrade_autoсодержит идентификаторы таких автовладельцев. MERGE INTO AUTO USING upgrade_auto as src ON (auto.personid=src.id and) WHEN MATCHED THEN UPDATE SET auto.model='Калина', auto.make='АвтоВАЗ'; -
В случае указания
<слияния без сопоставления>выполняется вставка всех строк из<исходной таблицы>в<целевую таблицу>, для которых не выполнено<условие слияния>. -
<Вставка строки>задает<список столбцов> <целевой таблицы>, в которые должны быть вставлены значения из<списка значений> <исходной таблицы>.Добавить в таблицу
AUTOинформацию о новых автовладельцах. MERGE INTO AUTO USING upgrade_auto as src ON (auto.personid=src.id) WHEN NOT MATCHED THEN INSERT (auto.personid, auto.model, auto.color) VALUES (src.id, src.mod_auto, src.color); -
На все операции вставки или обновления, указанные применительно к целевой таблице распространяются все ограничения, определенные для этой таблицы, включая все каскадные ограничения ссылочной целостности.
-
Для каждой операции вставки и обновления запускаются все соответствующие триггеры, определенные для целевой таблицы. Очередность запуска триггеров устанавливается ядром СУБД.
-
Если в
<целевой таблице>определены триггерыINSTEAD OF UPDATEилиINSTEAD OF INSERT, то операции обновления или добавления строк не выполняются. Вместо этого запускаются соответствующие триггеры. -
Чтобы полученные результаты были гарантированно верными, должны быть правильно указаны условия поиска, которые используются для сопоставления исходных и целевых строк. Рекомендуется придерживаться следующих правил:
-
укажите в предложении
ON <условие слияния>только те условия поиска, которые определяют критерий совпадения данных в исходных и целевых таблицах. То есть необходимо указать только те столбцы целевой таблицы, которые сравниваются с соответствующими столбцами исходной таблицы; -
не включайте сравнения с другими значениями, такими, как константа;
-
для фильтрации данных используйте представления.
-
Примеры
-
Одновременная корректировка и вставка записей.
MERGE INTO AUTO USING upgrade_auto as src ON (auto.personid=src.id and) WHEN MATCHED THEN UPDATE SET auto.model='Калина', auto.make='АвтоВАЗ' WHEN NOT MATCHED THEN INSERT (auto.personid, auto.model, auto.color) VALUES (src.id, src.mod_auto, src.color);
-
Использование вместо исходной таблицы подзапросов.
2.1 Обновить информацию только о пользователе c идентификатором 10 и 11 (без создания исходной таблицы).
MERGE INTO AUTO USING (SELECT 10 as id, 'HONDA'as mod_auto, 'GREEN'as color UNION SELECT 11 as id, 'BEANTLY' as mod_auto, 'RED'as color ) as src ON (auto.personid=src.id) WHEN MATCHED THEN UPDATE SET auto.model='Калина', auto.make='АвтоВАЗ' WHEN NOT MATCHED THEN INSERT (auto.personid, auto.model, auto.color) VALUES (src.id, src.mod_auto, src.color);2.2 Все владельцы автомобилей марки
MUSTANG BOSS 351белого цвета, проживающие в городеSAN FRANCISCO, перекрасили свои автомобили в черный цвет. Отразить этот факт в таблицеAUTO.a) составляем представление – список всех жителей города
SAN FRANCISCO, владеющих автомобилем маркиMUSTANG BOSS 351белого цвета:create or replace view ListAutoUser as select person.personid, person.city, auto.model from auto, person where person.personid=auto.personid and person.city='SAN FRANCISCO' and auto.model='MUSTANG BOSS 351' and auto.color='WHITE';
б) вносим изменение в таблицу
AUTOMERGE INTO AUTO USING (select personid as id from ListAutoUser) as src ON (auto.personid=src.id) WHEN MATCHED THEN UPDATE SET auto.color='BLACK';
-
Пусть есть таблица T с двумя целочисленными столбцами I и J:
I J - - | 1| 1| | 2| 1| | 3| 3| | 4| 4|
Выполняем слияние этой таблицы с собой:
merge into T using T as A on T.I = A.J when matched then update set T.J = T.J + 1 when not matched then insert (T.I, T.J) values (0, 0);
Результат:
I J - - | 1| 3| | 2| 1| | 3| 4| | 4| 5|
Добавление новых строк не произошло, т.к. для каждой строки исходной таблицы A (неважно, что она та же, что и целевая таблица) нашлась строка из T, в которой T.I = A.J. Именно поэтому при выполнении запроса всегда выполняется конструкция
when matched then, т.е. всегда только корректировка.К первой строке таблицы значение прибавлено дважды, т.к. для двух строк таблицы A (первая и вторая строка) в T нашлась одна строка (первая), для которой T.I = A.J, поэтому для этой первой строки замена производилась дважды.
-
Добавление в таблицу новых строк или корректировка существующих без использования исходной таблицы.
create or replace table "Count of children" (FIO char(15), total int); MERGE INTO "Count of children" AS child USING (VALUES('Иванов И. И.' FIO, 1 total)) AS details ON (child.FIO = details.FIO) WHEN MATCHED THEN UPDATE SET child.total = child.total + details.total WHEN NOT MATCHED THEN INSERT (child.FIO, child.total) VALUES (details.FIO, details.total); -
В разделе
INSERT,UPDATEимя целевой таблицы перед именем столбцов можно не указывать. Выше приведенный запрос можно написать так:MERGE INTO "Count of children" AS child USING (VALUES('Иванов И. И.' FIO, 1 total)) AS details ON (child.FIO = details.FIO) WHEN MATCHED THEN UPDATE SET total = total + details.total WHEN NOT MATCHED THEN INSERT (FIO, total) VALUES (details.FIO, details.total);