Ms sql merge пример: Операция MERGE в языке Transact-SQL – описание и примеры | Info-Comp.ru
Операция MERGE в языке Transact-SQL – описание и примеры | Info-Comp.ru
В языке Transact-SQL в одном ряду с такими операциями как INSERT (вставка), UPDATE (обновление), DELETE (удаление) стоит операция MERGE (слияние), которая в некоторых случаях может быть полезна, но некоторые почему-то о ней не знают и не пользуются ею, поэтому сегодня мы рассмотрим данную операцию и разберем примеры.
Начнем мы, конечно же, с небольшой теории.
Заметка! Начинающим рекомендую посмотреть мой видеокурс по T-SQL.
Что такое MERGE в T-SQL?
MERGE – операция в языке T-SQL, при которой происходит обновление, вставка или удаление данных в таблице на основе результатов соединения с данными другой таблицы или SQL запроса. Другими словами, с помощью MERGE можно осуществить слияние двух таблиц, т.е. синхронизировать их.
В операции MERGE происходит объединение по ключевому полю или полям основной таблицы (в которой и будут происходить все изменения) с соответствующими полями другой таблицы или результата запроса. В итоге если условие, по которому происходит объединение, истина (WHEN MATCHED), то мы можем выполнить операции обновления или удаления, если условие не истина, т.е. отсутствуют данные (WHEN NOT MATCHED), то мы можем выполнить операцию вставки (INSERT добавление данных), также если в основной таблице присутствуют данные, которое отсутствуют в таблице (или результате запроса) источника (WHEN NOT MATCHED BY SOURCE), то мы можем выполнить обновление или удаление таких данных.
В дополнение к основным перечисленным выше условиям можно указывать «Дополнительные условия поиска», они указываются через ключевое слово AND.
Упрощённый синтаксис MERGE
MERGE <Основная таблица> USING <Таблица или запрос источника> ON <Условия объединения> [ WHEN MATCHED [ AND <Доп. условие> ] THEN <UPDATE или DELETE> [ WHEN NOT MATCHED [ AND Доп. условие> ] THEN <INSERT> ] [ WHEN NOT MATCHED BY SOURCE [ AND <Доп. условие> ] THEN <UPDATE или DELETE> ] [ ...n ] [ OUTPUT ] ;
Важные моменты при использовании MERGE:
- В конце инструкции MERGE обязательно должна идти точка с запятой (;) иначе возникнет ошибка;
- Должно быть, по крайней мере, одно условие MATCHED;
- Операцию MERGE можно использовать совместно с CTE (обобщенным табличным выражением);
- В инструкции MERGE можно использовать ключевое слово OUTPUT, для того чтобы посмотреть какие изменения были внесены. Для идентификации операции здесь в OUTPUT можно использовать переменную $action;
- На все операции к основной таблице, которые предусмотрены в MERGE (удаления, вставки или обновления), действуют все ограничения, определенные для этой таблицы;
- Функция @@ROWCOUNT, если ее использовать после инструкции MERGE, будет возвращать общее количество вставленных, обновленных и удаленных строк;
- Для того чтобы использовать MERGE необходимо разрешение на INSERT, UPDATE или DELETE в основной таблице, и разрешение SELECT для таблицы источника;
- При использовании MERGE необходимо учитывать, что все триггеры AFTER на INSERT, UPDATE или DELETE, определенные для целевой таблицы, будут запускаться.
А теперь переходим к практике. И для начала давайте определимся с исходными данными.
Исходные данные для примеров операции MERGE
У меня в качестве SQL сервера будет выступать Microsoft SQL Server 2016 Express. На нем есть тестовая база данных, в которой я создаю тестовые таблицы, например, с товарами: TestTable – это у нас будет целевая таблица, т.е. та над которой мы будем производить все изменения, и TestTableDop – это таблица источник, т.е. данные в соответствии с чем, мы будем производить изменения.
Запрос для создания таблиц.
--Целевая таблица CREATE TABLE dbo.TestTable( ProductId INT NOT NULL, ProductName VARCHAR(50) NULL, Summa MONEY NULL, CONSTRAINT PK_TestTable PRIMARY KEY CLUSTERED (ProductId ASC) ) --Таблица источник CREATE TABLE dbo.TestTableDop( ProductId INT NOT NULL, ProductName VARCHAR(50) NULL, Summa MONEY NULL, CONSTRAINT PK_TestTableDop PRIMARY KEY CLUSTERED (ProductId ASC) )
Далее я их наполняю тестовыми данными.
--Добавляем данные в основную таблицу INSERT INTO dbo.TestTable (ProductId,ProductName,Summa) VALUES (1, 'Компьютер', 0) GO INSERT INTO dbo.TestTable (ProductId,ProductName,Summa) VALUES (2, 'Принтер', 0) GO INSERT INTO dbo.TestTable (ProductId,ProductName,Summa) VALUES (3, 'Монитор', 0) GO --Добавляем данные в таблицу источника INSERT INTO dbo.TestTableDop (ProductId,ProductName,Summa) VALUES (1, 'Компьютер', 500) GO INSERT INTO dbo.TestTableDop (ProductId,ProductName,Summa) VALUES (2, 'Принтер', 300) GO INSERT INTO dbo.TestTableDop (ProductId,ProductName,Summa) VALUES (4, 'Монитор', 400) GO
Посмотрим на эти данные.
SELECT * FROM dbo.TestTable SELECT * FROM dbo.TestTableDop
Видно, что в целевой таблице значение поля Summa = 0, а также есть несоответствие некоторых идентификаторов, т.е. у нас есть товары, которые есть в одной таблице, при этом они отсутствуют в другой.
Пример 1 – обновление и добавление данных с помощью MERGE
Это, наверное, классический вариант использования MERGE, когда мы по условию объединения обновляем данные, а если таких данных нет, то добавляем их. Для наглядности в конце инструкции MERGE я укажу ключевое слово OUTPUT, для того чтобы посмотреть какие именно изменения мы произвели, а также сделаю выборку итоговых данных.
MERGE dbo.TestTable AS T_Base --Целевая таблица USING dbo.TestTableDop AS T_Source --Таблица источник ON (T_Base.ProductId = T_Source.ProductId) --Условие объединения WHEN MATCHED THEN --Если истина (UPDATE) UPDATE SET ProductName = T_Source.ProductName, Summa = T_Source.Summa WHEN NOT MATCHED THEN --Если НЕ истина (INSERT) INSERT (ProductId, ProductName, Summa) VALUES (T_Source.ProductId, T_Source.ProductName, T_Source.Summa) --Посмотрим, что мы сделали OUTPUT $action AS [Операция], Inserted.ProductId, Inserted.ProductName AS ProductNameNEW, Inserted.Summa AS SummaNEW, Deleted.ProductName AS ProductNameOLD, Deleted.Summa AS SummaOLD; --Не забываем про точку с запятой --Итоговый результат SELECT * FROM dbo.TestTable SELECT * FROM dbo.TestTableDop
Мы видим, что у нас было две операции UPDATE и одна INSERT. Так оно и есть, две строки из таблицы TestTable соответствуют двум строкам в таблице TestTableDop, т.е. у них один и тот же ProductId, у данных строк в таблице TestTable мы обновили поля ProductName и Summa. При этом в таблице TestTableDop есть строка, которая отсутствует в TestTable, поэтому мы ее и добавили через INSERT.
Пример 2 – синхронизация таблиц с помощью MERGE
Теперь, допустим, нам нужно синхронизировать таблицу TestTable с таблицей TestTableDop, для этого мы добавим еще одно условие WHEN NOT MATCHED BY SOURCE, суть его в том, что мы удалим строки, которые есть в TestTable, но нет в TestTableDOP. Но для начала, для того чтобы у нас все три условия отработали (в частности WHEN NOT MATCHED) давайте в таблице TestTable удалим строку, которую мы добавили в предыдущем примере. Также здесь я в качестве источника укажу запрос, чтобы Вы видели, как можно использовать запросы в качестве источника.
--Удаление строки с ProductId = 4 --для того чтобы отработало условие WHEN NOT MATCHED DELETE dbo.TestTable WHERE ProductId = 4 --Запрос MERGE для синхронизации таблиц MERGE dbo.TestTable AS T_Base --Целевая таблица --Запрос в качестве источника USING (SELECT ProductId, ProductName, Summa FROM dbo.TestTableDop) AS T_Source (ProductId, ProductName, Summa) ON (T_Base.ProductId = T_Source.ProductId) --Условие объединения WHEN MATCHED THEN --Если истина (UPDATE) UPDATE SET ProductName = T_Source.ProductName, Summa = T_Source.Summa WHEN NOT MATCHED THEN --Если НЕ истина (INSERT) INSERT (ProductId, ProductName, Summa) VALUES (T_Source.ProductId, T_Source.ProductName, T_Source.Summa) --Удаляем строки, если их нет в TestTableDOP WHEN NOT MATCHED BY SOURCE THEN DELETE --Посмотрим, что мы сделали OUTPUT $action AS [Операция], Inserted.ProductId, Inserted.ProductName AS ProductNameNEW, Inserted.Summa AS SummaNEW,Deleted.ProductName AS ProductNameOLD, Deleted.Summa AS SummaOLD; --Не забываем про точку с запятой --Итоговый результат SELECT * FROM dbo.TestTable SELECT * FROM dbo.TestTableDop
В итоге мы видим, что у нас таблицы содержат одинаковые данные. Для этого мы выполнили две операции UPDATE, одну INSERT и одну DELETE. При этом мы использовали всего одну инструкцию MERGE.
Пример 3 – операция MERGE с дополнительным условием
Сейчас давайте выполним запрос похожий на запрос, который мы использовали в примере 1, только добавим дополнительное условие на обновление данных, например, мы будем обновлять TestTable только в том случае, если поле Summa, в TestTableDop, содержит какие-нибудь данные (например, мы не хотим использовать некорректные значения для обновления). Для того чтобы было видно, как отработало это условие, давайте предварительно очистим у одной строки в таблице TestTableDop поле Summa (поставим NULL).
--Очищаем поле сумма у одной строки в TestTableDop UPDATE dbo. TestTableDop SET Summa = NULL WHERE ProductId = 2 --Запрос MERGE MERGE dbo.TestTable AS T_Base --Целевая таблица USING dbo.TestTableDop AS T_Source --Таблица источник ON (T_Base.ProductId = T_Source.ProductId) --Условие объединения --Если истина + доп. условие отработало (UPDATE) WHEN MATCHED AND T_Source.Summa IS NOT NULL THEN UPDATE SET ProductName = T_Source.ProductName, Summa = T_Source.Summa WHEN NOT MATCHED THEN --Если НЕ истина (INSERT) INSERT (ProductId, ProductName, Summa) VALUES (T_Source.ProductId, T_Source.ProductName, T_Source.Summa) --Посмотрим, что мы сделали OUTPUT $action AS [Операция], Inserted.ProductId, Inserted.ProductName AS ProductNameNEW, Inserted.Summa AS SummaNEW, Deleted.ProductName AS ProductNameOLD, Deleted.Summa AS SummaOLD; --Не забываем про точку с запятой --Итоговый результат SELECT * FROM dbo.TestTable SELECT * FROM dbo.TestTableDop
В итоге у меня обновилось всего две строки, притом, что все три строки успешно выполнили условие объединения, но одна строка не обновилась, так как сработало дополнительное условие Summa IS NOT NULL, потому что поле Summa у строки с ProductId = 2, в таблице TestTableDop, не содержит никаких данных, т.е. NULL.
Заметка! Для комплексного изучения языка SQL и T-SQL рекомендую посмотреть мои видеокурсы по T-SQL, которые помогут Вам «с нуля» научиться работать с SQL и программировать на T-SQL в Microsoft SQL Server.
На этом у меня все, удачи!
Нравится8Не нравится
Объяснение оператора MERGE в SQL
Обязательное условие — заявление MERGE
Оператор MERGE в SQL, как обсуждалось ранее в предыдущем посте , представляет собой комбинацию трех операторов INSERT , DELETE и UPDATE . Таким образом, если есть таблица источника и таблица назначения , которые должны быть объединены, то с помощью оператора MERGE все три операции (INSERT, UPDATE, DELETE) могут выполняться одновременно.
Простой пример пояснит использование MERGE Statement.
Пример:
Предположим, есть две таблицы:
- PRODUCT_LIST — таблица, содержащая текущие сведения о продуктах, доступных с полями P_ID, P_NAME и P_PRICE, соответствующими идентификатору, названию и цене каждого продукта.
- UPDATED_LIST — таблица, содержащая новые сведения о продуктах, доступные в полях P_ID, P_NAME и P_PRICE, соответствующих идентификатору, названию и цене каждого продукта.
Задача состоит в том, чтобы обновить информацию о продуктах в PRODUCT_LIST в соответствии с UPDATED_LIST.
Решение
Теперь, чтобы объяснить этот пример лучше, давайте разделим пример на шаги.
- Шаг 1: Распознать ЦЕЛЬ и таблицу ИСТОЧНИК
Таким образом, в этом примере, поскольку его просят обновить продукты в PRODUCT_LIST согласно UPDATED_LIST, следовательно, PRODUCT_LIST будет действовать как TARGET, а UPDATED_LIST будет действовать как таблица SOURCE. - Шаг 2: Распознать выполняемые операции.
Теперь, как видно, между TARGET и таблицей SOURCE есть три несоответствия:- Стоимость КОФЕ в ЦЕЛЕ составляет 15.00, а в ИСТОЧНИКЕ — 25.00.
PRODUCT_LIST 102 COFFEE 15.00 UPDATED_LIST 102 COFFEE 25.00
- В SOURCE нет продукта BISCUIT, но он находится в TARGET
PRODUCT_LIST 103 BISCUIT 20.00
- В TARGET нет продукта CHIPS, но он находится в SOURCE
UPDATED_LIST 104 CHIPS 22.00
Следовательно, в TARGET необходимо выполнить три операции в соответствии с вышеуказанными несоответствиями. Они есть:
- UDPATE операция
102 COFFEE 25.00
- УДАЛИТЬ операцию
103 BISCUIT 20.00
- Операция вставки
104 CHIPS 22.00
- Стоимость КОФЕ в ЦЕЛЕ составляет 15.00, а в ИСТОЧНИКЕ — 25.00.
- Шаг 3: Напишите SQL-запрос.
Note: Refer this post for the syntax of MERGE statement.
SQL-запрос для выполнения вышеупомянутых операций с помощью оператора MERGE :
/* Selecting the Target
and
the Source */
MERGE PRODUCT_LIST
AS
TARGET
USING UPDATE_LIST
AS
SOURCE
/* 1. Performing the
UPDATE
operation */
/* If the P_ID
is
same,
check
for
change
in
P_NAME
or
P_PRICE */
ON
(TARGET.P_ID = SOURCE.P_ID)
WHEN
MATCHED
AND
TARGET.P_NAME <> SOURCE.P_NAME
OR
TARGET.P_PRICE <> SOURCE.P_PRICE
/*
Update
the records
in
TARGET */
THEN
UPDATE
SET
TARGET.P_NAME = SOURCE.P_NAME,
TARGET.P_PRICE = SOURCE.P_PRICE
/* 2. Performing the
INSERT
operation */
/*
When
no
records are matched
with
TARGET
table
Then
insert
the records
in
the target
table
*/
WHEN
NOT
MATCHED
BY
TARGET
THEN
INSERT
(P_ID, P_NAME, P_PRICE)
VALUES
(SOURCE.P_ID, SOURCE.P_NAME, SOURCE.P_PRICE)
/* 3. Performing the
DELETE
operation */
/*
When
no
records are matched
with
SOURCE
table
Then
delete
the records
from
the target
table
*/
WHEN
NOT
MATCHED
BY
SOURCE
THEN
DELETE
/*
END
OF
MERGE */
Выход:
PRODUCT_LIST P_ID P_NAME P_PRICE 101 TEA 10.00 102 COFFEE 25.00 104 CHIPS 22.00
Таким образом, таким образом все мы можем выполнить все эти три основных оператора в SQL вместе с помощью оператора MERGE.
Примечание. Любое имя, отличное от target и source, может использоваться в синтаксисе MERGE. Они используются только для того, чтобы дать вам лучшее объяснение.
Эта статья предоставлена Dimpy Varshni . Если вы как GeeksforGeeks и хотели бы внести свой вклад, вы также можете написать статью с помощью contribute.geeksforgeeks.org или по почте статьи [email protected]. Смотрите свою статью, появляющуюся на главной странице GeeksforGeeks, и помогите другим вундеркиндам.
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.
Рекомендуемые посты:
Объяснение оператора MERGE в SQL
0.00 (0%) 0 votes
Инструкция MERGE | sql-oracle.ru
Выполняется операция
UPDATE
, если строки существуют, и операцияINSERT
, если это новая строка:исключает необходимость в отдельных обновлениях;
повышается производительность и простота использования;
удобна в приложениях хранилища данных.
Сервером Oracle поддерживается инструкция MERGE
для операций INSERT
, UPDATE
и DELETE
. Используя эту инструкцию, можно обновить, вставить или удалить строку по условию в таблице, таким образом исключая необходимость применения нескольких инструкций DML. Решение о выполнении обновления, вставки или удаления в целевой таблице основывается на условии в предложении ON
.
Необходимо иметь объектные привилегии INSERT
и UPDATE
на целевую таблицу и объектную привилегию SELECT
на исходную таблицу. Чтобы задать предложение DELETE
для merge_update_clause
, необходимо также обладать объектной привилегией DELETE
на целевую таблицу.
Инструкция MERGE
является детерминированной. Одну и ту же строку целевой таблицы невозможно обновить несколько раз в одной и той же инструкции MERGE
.
Альтернативный подход состоит в использовании циклов PL/SQL и нескольких инструкций DML. Однако инструкцию MERGE
удобно использовать и проще выразить в виде одиночной инструкции SQL.
Инструкция MERGE
удобна в ряде приложений хранилища данных. Например, в приложении хранилища данных иногда возникает необходимость в работе с данными, поступающими из нескольких источников, часть из которых может быть дубликатами. Инструкция MERGE
позволяет добавлять и изменять строки по определенному условию.
Синтаксис инструкции MERGE
Используя инструкцию MERGE
, можно по определенному условию вставлять, обновлять и удалять строки в таблице.
Объединение строк
Используя инструкцию MERGE
, можно обновлять существующие строки и вставлять новые строки по определенному условию. Применяя инструкцию MERGE
, можно удалить устаревшие строки одновременно с обновлением строк в таблице. Чтобы сделать это, в синтаксис инструк- ции MERGE
включите предложение DELETE
со своим собственным предложением WHERE
.
Элементы синтаксиса:
Предложение
INTO
— задает целевую таблицу, которая обновляется или в которую выполняется вставка.Предложение
USING
— идентифицирует источник обновляемых или вставляемых данных; может быть таблицей, представлением или подзапросом.Предложение
ON
— условие, по которому операцияMERGE
выполняет обновление или вставку.WHEN MATCHED
|WHEN NOT MATCHED
— предписывает серверу, как реагировать на результаты условия объединения
Более подробно изложено в документации Oracle Database 11g SQL Reference (Справочник по SQL для базы данных Oracle 11g).
Далее: Функции TO_YMINTERVAL и TO_DSINTERVAL
Тонкости благополучного git-merge / Хабр
Вступительное слово
Считается, что «киллер фичей» СКВ Git является легковесное ветвление. Я ощутил это преимущество в полной мере, ведь я перешел на Git с SVN, где ветвление было достаточно дорогим процессом: для создания ветки нужно было скопировать весь рабочий каталог. В Git все проще: создание ветки подразумевает лишь создание нового указателя на определенный коммит в папке .git/refs/heads
, который является файлом с 40 байтами текста, хешем коммита.
Основными командами пользовательского уровня для ветвления в Git являются git-branch, git-checkout, git-rebase, git-log и, конечно же, git-merge. Для себя я считаю git-merge зоной наибольшей ответственности, точкой огромной магической энергии и больших возможностей. Но это достаточно сложная команда, и даже достаточно длительный опыт работы с Git порой бывает недостаточным для освоение всех ее тонкостей и умения применить ее наиболее эффективно в какой-либо нестандартной ситуации.
Попробуем же разобраться в тонкостях git-merge и приручить эту великую магию.
Здесь я хочу рассмотреть только случай благополучного слияния, под которым я понимаю слияние без конфликтов. Обработка и разрешение конфликтов — отдельная интересная тема, достойная отдельной статьи. Я очень рекомендую так же ознакомиться со статьей Внутреннее устройство Git: хранение данных и merge, содержащей много важной информации, на которую я опираюсь.
Анатомия команды
Если верить мануалу, команда имеет следующий синтаксис:
git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit] [-s <strategy>] [-X <strategy-option>] [--[no-]rerere-autoupdate] [-m <msg>] [<commit>...] git merge <msg> HEAD <commit>... git merge --abort
По большому счету, в Git есть два вида слияния: перемотка (fast-forward merge) и «истинное» слияние (true merge). Рассмотрим несколько примеров обоих случаев.
«Истинное» слияние (true merge)
Мы отклоняемся от ветки master, чтобы внести несколько багов улучшений. История коммитов у нас получилась следующая:
master: A - B - C - D \ feature: X - Y
Выполним на ветке master git merge feature
:
master: A - B - C - D - (M) \ / feature: X - Y
Это наиболее частый паттерн слияния. В данном случае в ветке master создается новый коммит (M), который будет ссылаться на двух родителей: коммит D и коммит Y; а указатель master установится на коммит (M). Таким образом Git будет понимать, какие изменения соответствуют коммиту (M) и какой коммит последний в ветке master. Обычно коммит слияния делается с сообщением вроде «Merge branch ‘feature’», но можно определить и свое сообщение коммита с помощью ключа -m
.
Посмотрим историю коммитов в тестовом репозитории, который я создал специально для этого случая:
$ git log --oneline 92384bd (M) bceb5a4 D 5dce5b1 Y 76f13e7 X d1920dc C 3a5c217 B 844af94 A
А теперь посмотрим информацию о коммите (M):
$ git cat-file -p 92384bd tree 2b5c78f9086384bd86a2ab9d00c7e41a56f01d04 parent bceb5a4ad88e80467404473b94c3e0758dd8e0be parent 5dce5b1edef64bd0d4e1039061a77be4d7182678 author Andre <[email protected]> 1380475972 +0400 committer Andre <[email protected]> 1380475972 +0400 (M)
Мы видим двух родителей, объект-дерево, соответствующее данному состоянию файлов репозитория, а так же информацию о том, кто виновен в коммите.
Посмотрим, куда ссылается указатель master:
$ cat .git/refs/heads/master 92384bd77304c09b81dcc4485da165923b96ed5f
Действительно, он теперь передвинут на коммит (M).
Squash и no-commit
Но что делать, если за содержимое ветки feature вас могут побить? К примеру, улучшение было небольшим, и вполне могло уместиться в один логичный коммит, но так вышло, что посреди работы вам было нужно убегать на электричку, а продолжать уже дома? В таком случае есть два выхода: экспорт репозитория с последующим импортом на другой машине, либо (особенно когда до электрички 10 минут, а до вокзала около километра) — сделать push origin feature
.
Заливать незаконченные коммиты в основную ветку плохо, и с этим нужно что-то делать. Одним из способов, и, пожалуй самым простым, является опция --squash
.
git merge feature --squash
объединит изменения всех коммитов ветки feature, перенесет их в ветку master и добавит в индекс. При этом коммит слияния не будет создан, вам нужно будет сделать его вручную.
Такого же поведения без параметра squash можно добиться, передав при слиянии параметр --no-commit
.
В случае применения такого слияния коммиты ветки feature не будут включены в нашу историю, но коммит Sq будет содержать все их изменения:
master: A - B - C - D - Sq \ feature: X - Y
Позже, в случае выполнения «классического» git merge feature
можно исправить это. Тогда история примет следующий вид:
master: A - B - C - D - Sq - (M) \ / feature: X - Y
В случае, если вы выполнили слияние без коммита, а потом поняли, что совершили фатальную ошибку, все можно отменить простой командой: git merge --abort
. Эта же команда может быть применена, если во время слияния произошли конфликты, а разрешать их в данный момент не хочется.
Перемотка (fast-forward merge)
Рассмотрим другой случай истории коммитов:
master: A - B - C \ feature: X - Y
Все как и в прошлый раз, но теперь в ветке master нет коммитов после ответвления. В этом случае происходит слияние fast-forward (перемотка). В этом случае отсутствует коммит слияния, указатель (ветка) master просто устанавливается на коммит Y, туда же указывает и ветка feature:
master, feature: A - B - C - X - Y
Чтобы предотвратить перемотку, можно использовать параметр --no-ff
.
В случае, если мы выполним git merge feature --no-ff -m '(M)'
, мы получим уже такую картину:
master: A - B - C - (M) \ / feature: X - Y
Если же для нас единственным приемлемым поведением является fast-forward, мы можем указать опцию --ff-only
. В этом случае, если к слиянию не применима перемотка, будет выведено сообщение о невозможности совершить слияние. Именно так было бы, если бы мы добавили опцию --ff-only
в самом первом примере, где после ответвления feature в ветке master был сделано коммит C.
Можно добавить, что при выполнении git pull origin branch_name
применяется как раз что-то вроде --ff-only
. То есть, в случае, если при слиянии с веткой origin/branch_name не приемлема перемотка, операция отменяется и выводится сообщении о невозможности выполнения.
Стратегии слияния
У команды git-merge есть интересный параметр, --strategy
, стратегия. Git поддерживает следующие стратегии слияния:
- resolve
- recursive
- ours
- octopus
- subtree
Стратегия resolve
Стратегия resolve — классическое трехсторонее слияние (three-way merge). Стандартный алгоритм трехстороннего слияния применяется для двух файлов с общим предком. Условно этот алгоритм можно представить в виде следующих шагов:
- поиск общего предка,
- поиск блоков, изменившихся в обеих версиях относительно общего предка,
- записываются блоки, оставшиеся без изменения,
- блоки, изменившиеся только в одном из потомков, записываются как измененные,
- блоки, изменившиеся в обеих версиях, записываются только если изменения идентичны, в ином случае объявляется конфликт, разрешение которого предоставляется пользователю.
Эта стратегия имеет один недостаток: в качестве общего предка двух веток всегда выбирается наиболее ранний общий коммит. Для случая из нашего первого примера это не страшно, можно смело применять git merge feature -s resolve
, и результат будет ожидаемым:
master: A - B - C - D - (M) \ / feature: X - Y
Здесь C — общий коммит двух веток, дерево файлов, соответствующее этому коммиту, принимается за общего предка. Анализируются изменения, произведенные в ветках master и feature со времен этого коммита, после чего для коммита (M) создается новая версия дерева файлов в соответствии с пунктами 4 и 5 нашего условного алгоритма.
В каком же случае проявляется недостаток стратегии resolve? Он проявляется в том случае, если для коммита (M) нам пришлось разрешить конфликты, после чего мы продолжили разработку и еще раз хотим выполнить git merge feature -s resolve
. В этом случае в качестве общего предка снова будет использован коммит C, и конфликты произойдут снова и будут нуждаться в нашем вмешательстве.
Стратегия recursive
Данная стратегия решает проблемы стратегии resolve. Она так же реализует трехстороннее слияние, но в качестве предка используется не реальный, а «виртуальный» предок, который конструируется по следующему условному алгоритму:
- проводится поиск всех кандидатов на общего предка,
- по цепочке проводится слияние кандидатов, в результате чего появляется новый «виртуальный» предок, причем более свежие коммиты имеют более высокий приоритет, что позволяет избежать повторного проявления конфликтов.
Результат этого действия принимается за общего предка и проводится трехсторонее слияние.
Для иллюстрации этой стратегии позаимствуем пример из статьи Merge recursive strategy из блога «The plasticscm blog»:
Итак, у нас есть две ветки: main и task001. И так вышло, что наши разработчики знают толк в извращениях: они слили коммит 15 из ветки main с коммитом 12 из ветки task001, а так же коммит 16 с коммитом 11. Когда нам понадобилось слить ветки, оказалось, что поиск реального предка — дело неблагодарное, но стратегия recursive с ее конструированием «виртуального» предка нам поможет. В результате мы получим следующую картину:
Стратегия recursive имеет множество опций, которые передаются команде git-merge
с помощью ключа -X
:
- ours и theirs
Используются для автоматического разрешения конфликтов. Ours — предпочитать «нашу» версию, версию «dst», theirs — предпочитать «их» версию. - renormalize (no-renormalize)
Предотвращает ложные конфликты при слиянии вариантов с разными типами перевода строк. - diff-algorithm=[patience|minimal|histogram|myers], а так же опция patience
Выбор алгоритма дифференциации файлов.
Дополнительную информацию об этих опциях можно найти в документации по git-diff. Если кратко, свойства этих алгоритмов следующие:
default, myers — стандартный, жадный алгоритм. Он используется по умолчанию.
minimal — производится поиск минимальнейших изменений, что занимает дополнительное время.
patience — использовать алгоритм «patience diff». О нем можно почитать у автора алгоритма, либо в сокращенном варианте на SO.
histogram — расширяет алгоритм patience с целью, описанной как «support low-occurrence common elements». Сказать честно, я не смог найти достаточно ясного ответа на вопрос, какие конкретно случаи подразумеваются и буду очень рад, если кто-нибудь поможет найти этот ответ. - ignore-space-change, ignore-all-space, ignore-space-at-eol
Корни этих опций лежат, опять же, в git-diff и относятся к дифференциации файлов при слиянии.
ignore-space-change — игнорируются различия в количестве пробелов, идущих подряд, а так же пробелы в конце строки,
ignore-all-space — пробелы абсолютно игнорируются при сравнении,
ignore-space-at-eol — игнорируются различия в пробелах в конце строки. - rename-threshold=<n>
Данная опция задает порог, по достижении которого файл может считаться не новым, а переименованным файлом, которого git-diff не досчитался. Например,-Xrename-threshold=90%
подразумевает, что переименованным считается файл, который содержит от 90% контента некоторого удаленного файла. - subtree[=<path>]
Выполнение рекурсивного слияния с этой опцией будет более продвинутым вариантом стратегии subtree, где алгоритм основывается на предположении, как деревья должны совместиться при слиянии. Вместо этого в этом случае указывается конкретный вариант.
Стратегия octopus
Эта стратегия используется для слияние более чем двух веток. Получившийся в итоге коммит будет иметь, соответственно, больше двух родителей.
Данная стратегия предполагает большую осторожность относительно потенциальных конфликтов. В связи с этим порой можно получить отказ в слиянии при применении стратегии octopus.
Стратегия ours
Не следует путать стратегию ours и опцию ours стратегии recursive.
Выполняя git merge -s ours obsolete
, вы как бы говорите: я хочу слить истории веток, но проигнорировать все изменения, которые произошли в ветке obsolete. Иногда рекомендуют вместо стратегии ours использовать следующий вариант:
$ git checkout obsolete $ git merge -s recursive -Xtheirs master
Стратегия ours — более радикальное средство.
Стратегия subtree
Для иллюстрации данной стратегии возьмем пример из главы Слияние поддеревьев книги «Pro Git».
Добавим в наш проект новые удаленный репозиторий, rack:
$ git remote add rack_remote [email protected]:schacon/rack.git $ git fetch rack_remote warning: no common commits remote: Counting objects: 3184, done. remote: Compressing objects: 100% (1465/1465), done. remote: Total 3184 (delta 1952), reused 2770 (delta 1675) Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done. Resolving deltas: 100% (1952/1952), done. From [email protected]:schacon/rack * [new branch] build -> rack_remote/build * [new branch] master -> rack_remote/master * [new branch] rack-0.4 -> rack_remote/rack-0.4 * [new branch] rack-0.9 -> rack_remote/rack-0.9 $ git checkout -b rack_branch rack_remote/master Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master. Switched to a new branch "rack_branch"
Ясно, что ветки master и rack_branch имеют абсолютно разные рабочие каталоги. Добавим файлы из rack_branch в master с использованием squash, чтобы избежать засорения истории ненужными нам фактами:
$ git checkout master $ git merge --squash -s subtree --no-commit rack_branch Squash commit -- not updating HEAD Automatic merge went well; stopped before committing as requested
Теперь файлы проекта rack у нас в рабочем каталоге.
Заключительное слово
Итак, я собрал вместе все знания, которые я получил за время работы с Git относительно благополучного git-merge. Я буду рад, если кому-то это поможет, но так же я буду рад, если кто-то поможет мне дополнить материал или исправить неточности и ошибки, если вдруг я допустил такие.
Обзор и примеры инструкции MERGE SQL Server
В этой статье мы рассмотрим оператор MERGE в SQL Server, альтернативы оператору MERGE, различные предложения и примеры оператора MERGE в SQL Server.
В этом посте мы рассмотрим следующие темы об операторе слияния SQL Server с некоторыми интересными примерами:
- Введение и синтаксис оператора слияния в SQL Server
- Использование оператора слияния для обновления, вставки и удаления строк в таблицах SQL Server
- Работа с предложением TOP в заявлении о слиянии
- OUTPUT в заявлении о слиянии
- Слияние с триггерами в SQL Server
Предложение
Заявление о слиянии Введение
Оператор MERGE используется для синхронизации двух таблиц путем вставки, удаления и обновления строк целевой таблицы на основе условия соединения с исходной таблицей.Давайте обсудим несколько примеров оператора MERGE с использованием демонстрационных таблиц.
Синтаксис MERGE
Ниже приведен синтаксис оператора MERGE в SQL Server.
MERGE TOP (значение) USING ON [WHEN MATCHED [AND THEN MATCHED [MATCHED BY NOT] [AND THEN [ЕСЛИ НЕ СООТВЕТСТВУЕТ ИСТОЧНИКУ [AND THEN [ ] ; |
Здесь я создаю образцы таблиц, чтобы показать различные примеры оператора MERGE.
Используйте нижеприведенный сценарий T-SQL для создания таблиц и вставки в них примеров данных.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Канал Стрит ‘) |
Использование MERGE для обновления совпавших строк
Предложение WHEN MATCHED в операторе MERGE SQL Server используется для обновления, удаления строк в целевой таблице, когда строки сопоставляются с исходной таблицей на основе условия соединения.В этом случае Locations является целевой таблицей, Locations_stage — исходной таблицей, а столбец LocationID используется в условии соединения. Пожалуйста, обратитесь к приведенному ниже сценарию T-SQL для обновления совпавших строк с помощью предложения WHEN MATCHED.
MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S НА T.LocationID = S.LocationID КОГДА СОБИРАЕТСЯ ТОГДА НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName; |
Строки с LocationID 1 и 3 сопоставляются в целевой и исходной таблице в соответствии с условием соединения, а значение LocationName в целевом объекте было обновлено значением LocationName в исходной таблице для обеих строк.
Мы также можем использовать дополнительное условие поиска вместе с предложением WHEN MATCHED в операторе MERGE SQL Server, чтобы обновлять только те строки, которые соответствуют дополнительному условию поиска.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 000 34 35 36 37 38 39 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ И T.LocationID = 3 ТОГДА УСТАНОВИТЬ ОБНОВЛЕНИЕ LocationName = S.LocationName; выберите * из местоположений |
Мы видим, что оператор слияния не обновил строку с LocationID 1, поскольку он не удовлетворял дополнительному условию поиска, указанному вместе с предложением WHEN MATCHED.
В лучшем случае мы можем указать только два предложения WHEN MATCHED в операторе MERGE.Если указаны два предложения WHEN MATCHED, одно предложение должно иметь операцию обновления, а другое — операцию удаления. Пожалуйста, обратитесь к приведенному ниже сценарию T-SQL для примера оператора MERGE с двумя предложениями WHEN MATCHED.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 000 34 35 36 37 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID ПРИ СООТВЕТСТВИИ И T.LocationID = 3 ТОГДА УДАЛИТЬ ПРИ СОГЛАСОВАНИИ И T.LocationID = 1 ТОГДА УСТАНОВИТЬ ОБНОВЛЕНИЕ LocationName = S.LocationName; |
- Примечание : мы не можем использовать одну и ту же операцию DML в обоих предложениях WHEN MATCHED.
Если в исходной таблице имеется более одной строки, которая соответствует условию соединения, обновление в инструкции MERGE SQL Server завершается ошибкой и возвращает ошибку «Оператор MERGE пытался ОБНОВИТЬ или УДАЛИТЬ одну и ту же строку более одного раза.Это происходит, когда целевая строка соответствует более чем одной исходной строке. Оператор MERGE не может ОБНОВЛЯТЬ / УДАЛИТЬ одну и ту же строку целевой таблицы несколько раз. Уточните предложение ON, чтобы целевая строка соответствовала не более одной исходной строке, или используйте предложение GROUP BY для группировки исходных строк ».
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 000 34 35 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘), (1,’ James Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ ЗАТЕМ НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName; |
Использование MERGE для вставки строк в целевую таблицу
Предложение WHEN NOT MATCHED BY TARGET используется для вставки в целевую таблицу строк, которые не соответствуют условию соединения с исходной таблицей. Предложение WHEN NOT MATCHED BY TARGET можно указать только один раз в операторе MERGE SQL Server.
Например, строка с LocationID = 4 в таблице Locations_stage не соответствует условию соединения и присутствует только в исходной таблице.Теперь, когда мы используем предложение WHEN NOT MATCHED BY TARGET в операторе слияния, чтобы вставить дополнительную строку из Locations_stage в Locations.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА НЕ СООТВЕТСТВУЕТ ЦЕЛИ ТОГДА INSERT (LocationID, LocationName) ЗНАЧЕНИЯ (S.LocationID, S.LocationName); |
Мы можем использовать дополнительное условие поиска для фильтрации строк, вставленных в целевую таблицу. В этом случае строки, которые не соответствуют условию соединения, но удовлетворяют дополнительному условию поиска, были только вставлены в целевую таблицу.
Использование MERGE для удаления строк в целевой таблице.
Мы можем использовать предложение WHEN NOT MATCHED BY SOURCE в операторе MERGE SQL Server, чтобы удалить строки в целевой таблице, которые не соответствуют условию соединения с исходной таблицей.
Например, строка с locationID = 2 в целевой таблице не соответствует условию соединения, и строка присутствует только в целевой таблице. Итак, когда мы используем WHEN NOT MATCHED BY SOURCE и можем либо удалить строку, либо обновить ее. Пожалуйста, обратитесь к приведенному ниже сценарию T-SQL, чтобы удалить строку в целевой таблице с помощью предложения WHEN NOT MATCHED BY SOURCE.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 000 34 35 36 37 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID ПРИ НЕ СООТВЕТСТВУЕТ ИСТОЧНИКУ ТО УДАЛИТЬ; |
Предложение WHEN NOT MATCHED BY SOURCE нельзя использовать более двух раз. Если предложение WHEN NOT MATCHED BY SOURCE в инструкции SQL Server MERGE было указано два раза, одна должна использовать операцию обновления, а другая должна использовать операцию удаления. Пожалуйста, обратитесь к сценарию T-SQL ниже, чтобы дважды использовать предложение WHEN NOT MATCHED BY SOURCE.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 000 34 35 36 37 38 39 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’), (6, ‘James Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘ Houston Street ‘), (4,’ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S НА T.LocationID = S.LocationID КОГДА НЕ СООТВЕТСТВУЕТ ИСТОЧНИКУ И LocationID = 2 ТОГДА УДАЛИТЬ ЕСЛИ НЕ СООТВЕТСТВУЕТ ИСТОЧНИКУ И LocationID = 6 ТОГДА ОБНОВИТЬ НАБОР LocationName = ‘Test’; |
Мы можем использовать все три предложения в одном операторе слияния для синхронизации целевой таблицы с исходной таблицей. Обратитесь к образцу сценария T-SQL, чтобы синхронизировать целевую таблицу с исходной таблицей с помощью оператора MERGE и всех трех предложений.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 41 42 43 44 45 46 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ ТОГДА НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName КОГДА НЕ СООТВЕТСТВУЕТ ЦЕЛИ ТОГДА INSERT (Location ) INSERT (Location ) , S.LocationName) ЕСЛИ ИСТОЧНИК НЕ СООТВЕТСТВУЕТ THEN DELETE; |
Предложение TOP в MERGE
Предложение TOP в операторе MERGE используется для ограничения количества затронутых строк.Предложение TOP применяется после удаления всех строк, которые не подходят для операций вставки, обновления и удаления. Пожалуйста, обратитесь к приведенному ниже сценарию T-SQL для инструкции SQL Server MERGE с предложением TOP.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 41 42 43 44 45 46 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘), () MERGE top (1) Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ ТОГДА НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName КОГДА НЕ СООТВЕТСТВУЕТ ЦЕЛИ ТОГДА INSERT (Location ) INSERT (Location ) , S.LocationName) ЕСЛИ ИСТОЧНИК НЕ СООТВЕТСТВУЕТ THEN DELETE; |
Мы можем видеть, что обновляется только строка с LocationID = 1, а строки, которые не были сопоставлены источником, не удаляются, а строки, которые не были сопоставлены целевым объектом, не вставляются.
Предложение
OUTPUT в MERGE
Предложение OUTPUT в операторе слияния вернет по одной строке для каждой строки, измененной в целевой таблице. $ action используется, чтобы узнать, была ли строка в целевой таблице удалена, вставлена или обновлена. Следующий сценарий T-SQL является примером предложения OUTPUT в операторе MERGE.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) MERGE Locations T ИСПОЛЬЗОВАНИЕ Locations_stage S ON T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ ТОГДА НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName КОГДА НЕ СООТВЕТСТВУЕТ ЦЕЛИ ТОГДА INSERT (Location ) INSERT (Location ) , S.LocationName) КОГДА НЕ СООТВЕТСТВУЕТ ИСТОЧНИКУ ТОГДА УДАЛИТЬ ВЫХОД УДАЛЕН. *, $ Action AS [Действие], ВСТАВЛЕНО. *; |
Пожалуйста, обратитесь к изображению ниже для вывода вышеуказанного сценария, который показывает действие, а также вставленные и удаленные данные в операторе MERGE SQL Server.вы также можете вставить выходные данные в другую таблицу, если вы хотите отслеживать или проверять изменения позже.
Использование MERGE для таблицы с триггерами
Если мы создаем вместо триггеров в целевой таблице, мы должны создавать вместо триггеров для всех действий DML, указанных в операторе MERGE. Если мы создадим только триггер INSTEAD OF INSERT для целевой таблицы и укажем операцию INSERT, DELETE И UPDATE в операторе MERGE, это вызовет ошибку.
Ниже приведен пример сценария T-SQL с триггером INSTEAD OF INSERT для целевой таблицы и всеми тремя операциями DML в операторе MERGE.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 41 42 43 44 45 46 49 0002 47 00030002 47 0003 51 52 53 54 55 56 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2, ‘Brigade Road’), (3, ‘Houston Street’) INSERT INTO Locations_stage values (1, ‘Richmond Cross’), (3, ‘Houston Street’), (4, ‘ Canal Street ‘) GO CREATE TRIGGER TEMP ON Locations INSTEAD OF INSERT AS BEGIN PRINT’ Hello ‘ END GE GE GE ИСПОЛЬЗОВАНИЕ Locations_stage S НА T.LocationID = S.LocationID КОГДА СООТВЕТСТВУЕТ ТОГДА НАБОР ОБНОВЛЕНИЯ LocationName = S.LocationName КОГДА НЕ СООТВЕТСТВУЕТ ЦЕЛИ ТОГДА INSERT (Location ) INSERT (Location ) , S.LocationName) ЕСЛИ ИСТОЧНИК НЕ СООТВЕТСТВУЕТ THEN DELETE; |
Пожалуйста, обратитесь к примеру ниже вместо триггера для всех действий, указанных в операторе слияния.
1 2 3 4 5 6 7 8 9 10 11 12 13 140002 14 18 19 20 21 22 23 24 25 26 27 28 29 30 000 34 35 36 37 38 39 40 41 42 43 44 45 46 49 00030002 47 00030002 47 0003 51 52 53 54 | ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.ТАБЛИЦЫ, где name = ‘Locations_stage’) BEGIN DROP TABLE Locations_stage END ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ SYS.TABLES, где name = ‘Locations’) BEGIN BEGIN СОЗДАТЬ ТАБЛИЦУ [dbo]. [Locations] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO СОЗДАТЬ ТАБЛИЦУ [dbo].[Locations_stage] ( [LocationID] [int] NULL, [LocationName] [varchar] (100) NULL ) GO INSERT INTO Locations values (1, ‘Richmond Road’) , (2 |
.
SQL Server 2008 Пример инструкции T-SQL MERGE
Microsoft SQL Server 2008 имеет усовершенствования T-SQL, такие как SQL MERGE statement , для разработчиков sql и администраторов баз данных SQL Server (DBA).
SQL Server 2008 MERGE T-SQL команду можно использовать для вставки, обновления и / или удаления в одном операторе sql.
Команда T-SQL Merge сравнит два набора данных или две таблицы.
Если есть совпадающие, то команда Merge обновит совпадающие.
Если есть несогласованные строки из одного набора данных в другой, тогда Merge вставит недостающие строки.
Команду слияния также можно использовать для удаления несовпадающих из основной таблицы.
Вот пример слияния, который следует запустить в базах данных MS SQL Server 2008, чтобы просмотреть результаты команды T-SQL MERGE.
СОЗДАТЬ ТАБЛИЦЫ Книги (
BookId smallint,
Заголовок varchar (100),
Автор varchar (25),
ISBN varchar (50),
Страницы int
)
GO
ВСТАВИТЬ В КНИГИ ЗНАЧЕНИЕ
(1, «Microsoft SQL Server 2005 для чайников», «Эндрю Ватт», NULL, NULL),
(2, 'Microsoft SQL Server 2005 для чайников', NULL, NULL, 432),
(3, «Microsoft SQL Server 2005 для чайников», NULL, «978-0-7645-7755-0», NULL)
GO
ВЫБРАТЬ * ИЗ Книг
Вот как данные в таблице sql Books отображаются после выполнения оператора SELECT.
Как разработчик T-SQL я хочу преобразовать указанные выше 3 строки данных в одну строку.
В некотором смысле я хочу сгруппировать эти столбцы, взяв за основу название книги.
Также я хочу объединить эти три строки в одну. Это означает, что при обновлении значений столбцов одной строки я должен избавиться от других строк таблицы.
Это означает, что я удалю повторяющиеся строки, взяв за основу название книги для сравнения всех строк таблицы sql.
Приведенный ниже оператор t-sql GROUP BY выбирает нужные мне данные, но не обновляет строку и не удаляет повторяющиеся строки в таблице sql.
ВЫБРАТЬ
МАКС (BookId) BookId,
Титул,
MAX (Автор) Автор,
МАКС. (ISBN) ISBN,
МАКС (страниц) Страниц
ИЗ Книги
ГРУППА ПО Титулу
Используя команду MS SQL Server 2008 T-SQL Merge, мы теперь создадим один единственный оператор, который обновит одну строку и удалит остальные из таблицы sql.
Вот код для примера слияния t-sql
MERGE Книги
ИСПОЛЬЗОВАНИЕ
(
ВЫБРАТЬ
МАКС (BookId) BookId,
Титул,
MAX (Автор) Автор,
МАКС. (ISBN) ISBN,
МАКС (страниц) Страниц
ИЗ Книги
ГРУППА ПО Титулу
) MergeData ON Books.BookId = MergeData.BookId
КОГДА СООТВЕТСТВОВАЛИ
НАБОР ОБНОВЛЕНИЙ
Книги.Title = MergeData.Title,
Books.Author = MergeData.Author,
Books.ISBN = MergeData.ISBN,
Books.Pages = MergeData.Pages
ЕСЛИ НЕ ПОДХОДИТ ПО ИСТОЧНИКУ, ТО УДАЛИТЬ;
GO
ВЫБРАТЬ * ИЗ Книг
И набор результатов вышеупомянутого оператора select после выполнения команды Merge такой же, как мы и планировали.
Надеюсь, вам понравился этот пример слияния T-SQL SQL Server 2008 T-SQL.
Вы можете найти аналогичный учебник по команде слияния в статье «Улучшение команды слияния T-SQL» и «Пример» в SQL Server 2008.
Также обратитесь к разделу «Слияние SQL в триггере» для получения дополнительных примеров команд слияния SQL Server.
Здесь утилита SQLCMD и команда SQL Merge используются вместе для создания удобного инструмента для администраторов баз данных.
.
Microsoft SQL Server — MERGE
Введение
Начиная с SQL Server 2008, можно выполнять операции вставки, обновления или удаления в одном операторе с помощью оператора MERGE.
Оператор MERGE позволяет объединить источник данных с целевой таблицей или представлением, а затем выполнить несколько действий с целью на основе результатов этого объединения.
Синтаксис
- Согласно MSDN — https: // msdn.microsoft.com/en-us/library/bb510625.aspx
[WITH[, … n]] MERGE [TOP (выражение)
[PERCENT]] [INTO][WITH ( )] [[
AS] псевдоним_таблицы] USINGON [
КОГДА ИМЕЕТСЯ [И <условие_поиска>] ТОГДА <совпадение_состава>]
[… n] [ЕСЛИ НЕ СОГЛАСОВАНО [ПО ЦЕЛИ] [И
] THEN ] [КОГДА НЕ
СООТВЕТСТВУЕТ ИСТОЧНИКУ [И] THEN
] […n] [ ] [OPTION (
[, … n])]; :: = {[имя_базы_данных.
schema_name. | schema_name. ] target_table}:: = {{[
[, … n]] [[,] ИНДЕКС (index_val [, … n]
)]}}:: = {table_or_view_name [[AS] псевдоним_таблицы
] [] [WITH (table_hint [[,] … n])] |
rowset_function [[AS] псевдоним_таблицы] [(псевдоним_колонки [,…n
])] | user_defined_function [[AS] псевдоним_таблицы] | OPENXML
| производная_таблица [AS] псевдоним_таблицы [(псевдоним_столбца
[, … n])] || |
}:: = :: =
{UPDATE SET| УДАЛИТЬ} :: = SET {
column_name = {выражение | ПО УМОЛЧАНИЮ | NULL} | {udt_column_name. {{
имя_свойства = выражение | field_name = выражение} | имя_метода
(аргумент [,.= |
| =} выражение} [, … n] <слияние_не совпадений> :: = {INSERT [(
список_столбцов)] {ЗНАЧЕНИЯ (список_значений) | ЗНАЧЕНИЯ ПО УМОЛЧАНИЮ } }
<условие_поиска> :: = <условие_поиска> :: = {[НЕ] | (
<условие_поиска>)} [{И | ИЛИ} [НЕ] {| (
)}] [, … n] :: = {выражение {= | <> | ! = | | > = | ! > | <| <= | ! <} выражение | строковое_выражение [НЕ] КАК строковое_выражение [ESCAPE 'escape_character'] | выражение [ НЕ] МЕЖДУ выражением И выражением | выражение IS [NOT] NULL | СОДЕРЖИТ ({столбец | *}, '
‘) |
FREETEXT ({столбец | *}, ‘freetext_string’) | выражение [НЕ]
IN (подзапрос | выражение [,…n]) | выражение {= | <> | ! = |
| > = | ! > | <| <= | ! <} {ВСЕ | НЕКОТОРЫЕ | ЛЮБОЙ} (подзапрос) | EXISTS (подзапрос)}:: = {[OUTPUT
INTO {@table_variable | output_table} [(column_list)]] [ВЫВОД
]} :: = { |
скалярное_выражение} [[AS] идентификатор_алиас_столбца] [, … n]
<имя_столбца> :: = {УДАЛЕНО | ВСТАВЛЕННЫЙ | from_table_name}.{* |
column_name} | $ действие
Выполняет операции вставки, обновления или удаления в целевой таблице на основе результатов соединения с исходной таблицей. Например, вы можете синхронизировать две таблицы, вставляя, обновляя или удаляя строки в одной таблице на основе различий, обнаруженных в другой таблице.
.
SELECT, INSERT, UPDATE с оператором SQL MERGE
Введение
Разработчики Business Intelligence называют это медленно
изменение размера. Разработчики баз данных называют это
UPSERT
. Будь то медленно меняющийся
размер или UPSERT
, базовый образец
остается прежним: ОБНОВЛЕНИЕ
данных, если ключ существует
и если ключ не существует ВСТАВЬТЕ
данные.
Это утомительный код для написания, сложный код для поддержки и
медленно выполнять.Однако, начиная с SQL Server 2008,
шаблон был заключен в новый MERGE
Утверждение. Я собираюсь продемонстрировать, как и когда использовать
новый отчет TSQL MERGE
. Я собираюсь начать
с некоторой предысторией на UPSERTs
и замедлении
изменение размеров.
UPSERTS и медленно меняющиеся размеры
Как я упоминал ранее, UPSERTS
и медленно
Изменение размеров — это термины для добавления или альтернативы
обновление записи в базе данных в зависимости от того,
запись существует или не существует.Обычно решение
алгоритм работает примерно так:
- Поиск записи с помощью ключа таблицы
- Если значение ключа отсутствует, вставить новую запись
- Если значение ключа существует, обновить запись
Для таблицы, подобной приведенной ниже:
СОЗДАТЬ ТАБЛИЦУ [dbo]. [ToMergeTable] ( [KeyField] [int] НЕ NULL, [Поле1] [nvarchar] (50) НЕ ПУСТО, [Поле2] [nvarchar] (50) НЕ NULL, [UpdateDateField] [datetime] НЕ ПУСТО, ОГРАНИЧЕНИЕ [PK_ToMergeTable] ПЕРВИЧНЫЙ КЛЮЧ КЛАСТЕРИРОВАН ( [KeyField] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) НА [ПЕРВИЧНОМ] Код TSQL может выглядеть так, как показано ниже.ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ * ИЗ ToMergeTable, ГДЕ KeyField = @KeyField) НАЧАТЬ ОБНОВЛЕНИЕ ToMergeTable SET UpdateDateField = GETDATE () WHERE KeyField = @KeyField ВЫБЕРИТЕ "ОБНОВЛЕНИЕ" КОНЕЦ ELSE НАЧАТЬ ВСТАВИТЬ В ToMergeTable (KeyField, Field1, Field2, UpdateDateField) VALUES (@ KeyField, @ Field1 + '- 1', @ Field2 + '- 1', GETDATE ()) ВЫБЕРИТЕ 'Сделано INSERT' КОНЕЦ
Нет ничего технически неправильного в заявлении
выше, но есть ряд недостатков в
решение.
Сначала оператор SELECT
отделяется
из INSERT
и UPDATE
заявление.Базы данных обычно имеют одновременных пользователей. в
время между выполнением SELECT
и, для
Например, оператор INSERT
, другой пользователь может
добавили новую запись через долю секунды после
SELECT
инструкция выполняет одну из
ВСТАВКИ
не работают.
Кроме того, приведенный выше код требует двух циклических обращений к
база данных; одна поездка, чтобы найти запись,
SELECT
инструкция и вторая поездка для выполнения
соответствующий DML
( ОБНОВЛЕНИЕ
или
ВСТАВИТЬ
).Кроме того, код работает только на одном
запись за раз.
Я мог бы внести некоторые улучшения в код, но несмотря ни на что
улучшения, которые я делаю, должны выполняться два утверждения. За
Например, код можно изменить для использования временной таблицы
и коррелированный подзапрос к INSERT
, если
данные временной таблицы отсутствуют и ОБНОВЛЕНИЕ
данные временной таблицы совпадают с чем-то в
WHERE
существующая таблица.
Опять же, улучшения кодирования технически верны
и более гибкий.Однако часто кодирование подзапроса
жертвует удобочитаемостью, плюс, как я упоминал ранее,
не избежать выполнения как минимум двух операторов и кодирования
более одного утверждения означает два предложения WHERE
сохранить, если ключ изменится.
С примером без MERGE
и со сценарием MERGE
я собираюсь
чтобы объяснить, как решение улучшается с MERGE
заявление.
Обзор MERGE
Ниже приведен алгоритм решения выше, реализованный с использованием
заявление MERGE
.
ОБЪЕДИНИТЬ В ToMergeTable как T ИСПОЛЬЗОВАНИЕ (ЗНАЧЕНИЯ (@ KeyField, @ Field1 + '- 1', @ Field2 + '- 1', GETDATE ()) , (@ KeyField + 1, @ Field1 + '- 2', @ Field2 + '- 2', GETDATE ()) , (@ KeyField + 2, @ Field1 + '- 3', @ Field2 + '- 3', GETDATE ()) ) AS S (KeyField, Поле1, Поле2, UpdateDate) ВКЛ T.KeyField = S.KeyField КОГДА ИМЕЕТСЯ ТО - ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ НАБОР UpdateDateField = UpdateDate КОГДА НЕ СООТВЕТСТВУЕТ - ВСТАВЬТЕ INSERT (KeyField, Field1, Field2, UpdateDateField) VALUES (S.KeyField, S.Field1, S.Field2, UpdateDate) OUTPUT $ action КАК ChangesMade;
Позже в этой статье я объясню, что каждая часть
заявление делает, сначала некоторые общие мысли.Целиком
решение заключено в один оператор. Итак, нет
разделение операторов и отсутствие необходимости запускать более
одно заявление. Улучшается читаемость и ремонтопригодность.
Более того, MERGE
существует по несколько более высокой цене.
уровень абстракции, чем SELECT
,
ВСТАВИТЬ
, ОБНОВЛЕНИЕ
. Это не загадка
что более высокие уровни абстракции часто приводят к более быстрому
разработка и лучшее сопровождение кода. Одно заявление
означает, что код выполняется в неявной транзакции.Два
отдельные заявления могли потребовать
BEGIN / COMMIT / ROLLBACK
транзакция.
Теперь я собираюсь показать, как составить утверждение выше.
и объясните варианты каждого раздела утверждения.
.