powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Merge возможен при условиях
12 сообщений из 12, страница 1 из 1
Merge возможен при условиях
    #40127206
Диана Орел
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.
Хочу использовать оператор merge в обновлении таблицы.
Условие такое: в таблице 5 полей (mag_id, val1_id, val2_id, ver_id, year_id). Когда добавляются в таблицу target_table данные, то если ver_id и year_id совпадают c ver_id, year_id в таблице source_table, то старые данные по ver_id и year_id надо удалить из target_table и вставить все данные из source_table. Если ver_id и year_id не совпадают, то данные из source_table добавляются в target_table.
Если использовать условие соединения (ON) по всем 5 полям, то получается соединение один-к-одному:
Код: sql
1.
2.
3.
4.
5.
merge target_table AS t1
using source_table AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id  and t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)
WHEN MATCHED then update set t1.summ_q1 = t2.summ_q1 
WHEN NOT MATCHED by source and (t1.[VER_ID] = t2.ver_id or t1.year_id = t2.year_id) then delete
WHEN NOT MATCHED by target and (t1.[VER_ID] <> t2.ver_id or t1.year_id <> t2.year_id) then insert (...)



ошибка:
авторMsg 5333, Level 16, State 2, Line 54
The identifier 't1.VER_ID' cannot be bound. Only source columns and columns in the clause scope are allowed in the 'WHEN NOT MATCHED' clause of a MERGE statement.
Msg 5333, Level 16, State 2, Line 54
The identifier 't1.year_id' cannot be bound. Only source columns and columns in the clause scope are allowed in the 'WHEN NOT MATCHED' clause of a MERGE statement.
Msg 5334, Level 16, State 2, Line 53
The identifier 't2.ver_id' cannot be bound. Only target columns and columns in the clause scope are allowed in the 'WHEN NOT MATCHED BY SOURCE' clause of a MERGE statement.
Msg 5334, Level 16, State 2, Line 53
The identifier 't2.year_id' cannot be bound. Only target columns and columns in the clause scope are allowed in the 'WHEN NOT MATCHED BY SOURCE' clause of a MERGE statement.

Если использовать соединение по 2м полям ver_id, year_id, то получается соединение много-ко-многим
Код: sql
1.
2.
3.
4.
5.
merge target_table AS t1
using source_table AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id )
WHEN MATCHED and (t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)then update set t1.summ_q1 = t2.summ_q1
WHEN MATCHED  and (t1.mag_id <> t2.mag_id or t1.val1_id <> t2.val1_id or t1.val2_id <> t2.val2_id) then delete
WHEN NOT MATCHED by target  then insert (...)




Ошибка:
авторMsg 8672, Level 16, State 1, Line 21
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127237
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если не фантазировать, а прочесть таки эти сраные мануалы:

"merge работает ТОЛЬКО по принципу ОДНА строка таргета <-> ОДНОЙ строке соурс."

Поэтому, для получения желаемой пены у рта надо тупо пронумеровать строки таргета и соурса

Код: sql
1.
2.
3.
4.
5.
6.
with t as ( select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from target_table )
    , x as (  select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from source_table )
merge t using x on t.ver_id = x.ver_id and t.year_id = x.year_id and t.n = x.n
WHEN MATCHED then update set summ_q1 = x.summ_q1
WHEN not MATCHED by source then delete
WHEN NOT MATCHED by target  then insert (...)
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127240
Alex_Va
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222

Код: sql
1.
2.
3.
(...)
WHEN not MATCHED by source then delete
(...)



а это для чего?
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127242
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Диана Орел
то старые данные по ver_id и year_id надо удалить из target_table

Наверное... за вот этим?
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127263
Диана Орел
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,
Спасибо за идею!!! (жаль, сама не догадалась. )
Вопрос, что означает order by 1/0?

Запрос у меня получился такой:

Код: sql
1.
2.
3.
4.
5.
6.
7.
with t as (select *, n = ROW_NUMBER()over(partition by year_id, ver_id order by 1/0) from source_table),
x as (select *, n = ROW_NUMBER()over(partition by year_id, hype_version_id order by 1/0) from target_table )
merge t as t1
using x AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id and t1.n = t2.n)
WHEN MATCHED and (t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)then update set t1.summ_q1 = t2.summ_q1
WHEN MATCHED  and (t1.mag_id <> t2.mag_id or t1.val1_id <> t2.val1_id or t1.val2_id <> t2.val2_id) then delete
WHEN NOT MATCHED by target then insert ()


то есть:
- если все 5 полей одинаковы, то обновление строки
- если только версия и год одинаковы, а любое из 3х полей отличается, то удаляем строку
- если нет такой версии и года, то добавляем строку
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127284
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Диана Орел
aleks222,
Спасибо за идею!!! (жаль, сама не догадалась. )
Вопрос, что означает order by 1/0?

Запрос у меня получился такой:

Код: sql
1.
2.
3.
4.
5.
6.
7.
with t as (select *, n = ROW_NUMBER()over(partition by year_id, ver_id order by 1/0) from source_table),
x as (select *, n = ROW_NUMBER()over(partition by year_id, hype_version_id order by 1/0) from target_table )
merge t as t1
using x AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id and t1.n = t2.n)
WHEN MATCHED and (t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)then update set t1.summ_q1 = t2.summ_q1
WHEN MATCHED  and (t1.mag_id <> t2.mag_id or t1.val1_id <> t2.val1_id or t1.val2_id <> t2.val2_id) then delete
WHEN NOT MATCHED by target then insert ()


то есть:
- если все 5 полей одинаковы, то обновление строки
- если только версия и год одинаковы, а любое из 3х полей отличается, то удаляем строку
- если нет такой версии и года, то добавляем строку


Незамутненный бред.
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127301
SERG1257
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Диана ОрелВопрос, что означает order by 1/0?
https://sqlperformance.com/2019/11/t-sql-queries/row-numbers-with-nondeterministic-order
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127353
Диана Орел
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,
поняла ваш вариант, наконец, я добавила условие, но видимо вы так подразумавали
Код: sql
1.
2.
3.
4.
5.
6.
with t as ( select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from target_table )
    , x as (  select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from source_table )
merge t using x on t.ver_id = x.ver_id and t.year_id = x.year_id and t.n = x.n
WHEN MATCHED then update set t.mag_id = x.mag_id, t.val1_id = x.val1_id, t.val2_id = x.val2_id, t.summ_q1 = x.summ_q1
WHEN not MATCHED by source then delete
WHEN NOT MATCHED by target  then insert (...)



- если версия и год совпадают, то все остальные поля обновить
- если нет такой строки в исходной таблице, то ужалить строку
- если нет такой строки в целевой таблице, то вставить

Сравню планы выполнения
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127354
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Диана Орел
aleks222,
поняла ваш вариант, наконец, я добавила условие, но видимо вы так подразумавали
Код: sql
1.
2.
3.
4.
5.
6.
with t as ( select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from target_table )
    , x as (  select *, n = row_number() over(partion by ver_id, year_id order by 1/0 ) from source_table )
merge t using x on t.ver_id = x.ver_id and t.year_id = x.year_id and t.n = x.n
WHEN MATCHED then update set t.mag_id = x.mag_id, t.val1_id = x.val1_id, t.val2_id = x.val2_id, t.summ_q1 = x.summ_q1
WHEN not MATCHED by source then delete
WHEN NOT MATCHED by target  then insert (...)



- если версия и год совпадают, то все остальные поля обновить
- если нет такой строки в исходной таблице, то ужалить строку
- если нет такой строки в целевой таблице, то вставить

Сравню планы выполнения

Ну, осталось савсем немного... до просветления...
А там, можно и нумерацию похерить.
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127369
Диана Орел
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222, без ROW_NUMBER()

Код: sql
1.
2.
3.
4.
5.
6.
7.
DECLARE @ver_id int, @year_id int;
with x as (select @ver_id = ver_id, @year_id = year_id, mag_id, va1_id, val2_id, summ_q1 from source_table)
merge target_table AS t1
using  x AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id  and t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)
WHEN MATCHED then update set t1.summ_q1 = t2.summ_q1 
WHEN NOT MATCHED by source and (t1.[VER_ID] = @ver_id and t1.year_id = @year_id) then delete
WHEN NOT MATCHED by target  then insert (...)
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127372
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Диана Орел
aleks222, без ROW_NUMBER()

Код: sql
1.
2.
3.
4.
5.
6.
7.
DECLARE @ver_id int, @year_id int;
with x as (select @ver_id = ver_id, @year_id = year_id, mag_id, va1_id, val2_id, summ_q1 from source_table)
merge target_table AS t1
using  x AS t2 on (t1.[VER_ID] = t2.ver_id and t1.year_id = t2.year_id  and t1.mag_id = t2.mag_id and t1.val1_id = t2.val1_id and t1.val2_id = t2.val2_id)
WHEN MATCHED then update set t1.summ_q1 = t2.summ_q1 
WHEN NOT MATCHED by source and (t1.[VER_ID] = @ver_id or t1.year_id = @year_id) then delete
WHEN NOT MATCHED by target  then insert (...)


Позор.

Код: sql
1.
2.
3.
4.
5.
6.
with x as (  select *  from source_table )
    , t as ( select * from target_table where exists( select * from x where t.ver_id = x.ver_id and t.year_id = x.year_id ) )
merge t using  x  on t.ver_id = x.ver_id and t.year_id = x.year_id  and t.mag_id = x.mag_id and t.val1_id = x.val1_id and t.val2_id = x.val2_id
WHEN MATCHED then update set summ_q1 = x.summ_q1 
WHEN NOT MATCHED by source then delete
WHEN NOT MATCHED by target  then insert (...)
...
Рейтинг: 0 / 0
Merge возможен при условиях
    #40127381
Диана Орел
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222

Код: sql
1.
2.
3.
4.
5.
6.
with x as (  select *  from source_table )
    , t as ( select * from target_table where exists( select * from x where t.ver_id = x.ver_id and t.year_id = x.year_id ) )
merge t using  x  on t.ver_id = x.ver_id and t.year_id = x.year_id  and t.mag_id = x.mag_id and t.val1_id = x.val1_id and t.val2_id = x.val2_id
WHEN MATCHED then update set summ_q1 = x.summ_q1 
WHEN NOT MATCHED by source then delete
WHEN NOT MATCHED by target  then insert (...)



круто, спасибо за опыт
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Merge возможен при условиях
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]