Новый оператор обновления базы данных MERGE
В приложениях SQL-ориентированных баз данных часто возникает потребность в передаче множества строк из таблицы, обновлявшейся при выполнении транзакции (транзакционной таблицы), в некоторую основную таблицу базы данных. Обычно транзакционная таблица содержит обновленные варианты строк, существующих в основной таблице, а также, возможно, новые строки, которые должны быть занесены в основную таблицу. При наличии традиционных средств обновления базы данных содержимое транзакционной таблицы может быть перенесено в основную таблицу путем выполнения двух отдельных шагов. На первом шаге требуется выполнить оператор UPDATE для всех строк основной таблицы, для которых имеются модифицированные “двойники” в транзакционной таблице. Затем нужно выполнить оператор INSERT для занесения в основную таблицу всех строк транзакционной таблицы, для которых таких двойников нет. Оператор MERGE, введенный в SQL:2003, позволяет выполнить такую операцию за один шаг, более эффективный и проще специфицируемый. Вот общий синтаксис этого нового оператора в немного упрощенной форме:
MERGE INTO table_name [ [ AS ] correlation_name ]
USING table_reference
ON conditional_expression merge_operation_specification
merge_operation_specification ::=
{ merge_when_matched_clause | merge when not matched clause }
| merge_when_matched_clause merge_when_not_matched_clause
| merge_when_not_matched_clause merge_when_matched_clause
merge_when_matched_clause ::=
WHEN MATCHED THEN UPDATE SET update_assignment_commalist
merge_when_not_matched_clause ::=
WHEN NOT MATCHED THEN INSERT [ ( column_commalist ) ]
VALUES ( value_expression_commalist )
Как видно из синтаксиса, в операторе обязательно содержится условное выражение и, по крайней мере, один из разделов “слияния при наличии сопоставления” (merge_when_matched_clause) и “слияния при отсутствии сопоставления” (merge when not matched clause). Пусть T1 обозначает таблицу, указанную в разделе USING, а T2 – имя таблицы, указанной в разделе INTO. Тогда семантика выполнения операции определяется следующим образом:
Во-вторых, очевидным образом не просматриваются разумные способы использования оператора MERGE, отличные от тривиальных случаев.
Приведем пример тривиального (хотя и вполне полезного и осмысленного) использования оператора. Предположим, что в базе данных предприятия поддерживается сводная таблица INVENTORY (инвентарная ведомость), содержащая данные обо всех деталях, которые имеются на предприятии. Дополнительные детали поступают на предприятие путем поставок от поставщиков, причем каждой поставке соответствует транзакционная таблица SHIPMENT. В завершение транзакции поставки требуется “перелить” данные из таблицы SHIPMENT в таблицу INVENTORY. Пусть таблицы SHIPMENT и INVENTORY имеют одну и ту же структуру, а наполнение их такое, какое показано на рис. 3.
INVENTORY
PART_NO
SHIPMENT
MERGE INTO INVENTORY ...
Рис. 3. Пример использования оператора MERGE
В обеих таблицах столбец PART_NO
является первичным ключом, а столбец PART_QUANTITY содержит данные о числе деталей в инвентарной ведомости или в поставке. Тогда в результате выполнения приведенного ниже оператора MERGE таблица INVENTORY
примет вид, показанный в нижней части рис. 3.
MERGE INTO INVENTORY AS INV
USING (SELECT PART_NO, PART_NAME, PART_QUANTITY FROM SHIPMENT) AS SH
ON (INV.PART_NO = SH.PART_NO)
WHEN MARCHED THEN UPDATE
SET PART_QUANTITY = INV.PART_QUANTUTY + SH.PART_QUANTITY
WHEN NOT MARCHED THEN INSERT
(PART_NO, PART_NAME, PART_QUANTITY)
VALUES (SH.PART_NO, SH.PART_NAME, SH.PART_QUANTITY) ;