Я хочу использовать merge
, и меня пугает это предупреждение от ссылки относительно условия соединения ON
:
Важно указывать только столбцы из целевой таблицы, которые
используются для соответствия целей. То есть укажите столбцы из
целевой таблицы, которые сравниваются с соответствующим столбцом
исходная таблица. Не пытайтесь улучшить производительность запросов с помощью фильтрации
строк в целевой таблице в предложении ON, например, указав
И НЕ target_table.column_x = значение. Это может привести к неожиданному возвращению
и неверные результаты.
Вот пример:
-- drop table trg
create table trg(department int not null,student int not null,name nvarchar(20))
alter table trg add constraint PK_trg primary key clustered (department,student)
insert trg values (12,0,'Tony'),(12,1,'Helen'),(55,0,'Tony'),(55,1,'Helen')
-- drop table src
go
create table src(student int not null,name nvarchar(20))
go
alter table src add constraint PK_src primary key clustered (student)
go
insert src values (0,'Antony'),(1,'Helen'),(2,'Mike')
select * from trg
select * from src
Таблица ТРГ
+------------+---------+-------+
| department | student | name |
+------------+---------+-------+
| 12 | 0 | Tony |
| 12 | 1 | Helen |
| 55 | 0 | Tony |
| 55 | 1 | Helen |
+------------+---------+-------+
Имеет 2 студентов на двух факультетах (пожалуйста, игнорируйте нарушение 2nf, третий столбец тоже должен зависеть от факультета, но сейчас я не могу вспомнить пример).
Теперь у нас есть таблица src
, в которой есть только информация относительно отдела 12:
+---------+--------+
| student | name |
+---------+--------+
| 0 | Antony |
| 1 | Helen |
| 2 | Mike |
+---------+--------+
... и мы хотим сохранить эту информацию в src
с merge
.
Используя это:
merge trg using src on trg.student=src.student and trg.department=12
when matched then update set name=src.name
when not matched by target then insert values (12,src.student,src.name)
;
Делает то, что мы намеревались. Таблица trg теперь имеет желаемый результат:
+------------+---------+--------+
| department | student | name |
+------------+---------+--------+
| 12 | 0 | Antony |
| 12 | 1 | Helen |
| 12 | 2 | Mike |
| 55 | 0 | Tony |
| 55 | 1 | Helen |
+------------+---------+--------+
Мы видим, что в отделе 12 Тони изменили имя на Антоний, в Майк добавили отдел 12, и больше ничего не произошло. Это было сделано нарушением предупреждения ссылки. Это нормально?
Полагаю, это можно переписать так:
merge trg using src on trg.student=src.student
when matched and trg.department=12 then update set name=src.name
when not matched by target then insert values (12,src.student,src.name);
Что действительно также работает правильно.
Является ли первый способ, который противоречит предупреждению, неправильным или плохой практикой? Почему?