Гость
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / MERGE WHEN MATCHED UPDATE+INSERT / 7 сообщений из 7, страница 1 из 1
16.06.2021, 19:03
    #40078009
Двоичник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Помогите пожалуйста разобраться, не могу совладать со скриптом

Пытаюсь соблюсти версионирование записей для мастер системы системы в своем ХД.

Таким образом вынимаю данные из таблицы, и складываю в свою БД. Но и добавляю признаки.
В мастерсистеме запись сохраняет свой идентификатор, но при этом актуализирует поле версии, удаляя предыдущую запись.

Моя задача далее сделать MERGE по основному признаку, и по косвенному понимать, изменилась ли запись

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
declare @m bigint select @m = IsNull(max(_Version), 0) from TTarget
declare @ts datetime = getdate()


MERGE INTO TTarget AS Target  
USING (select 
       [_IDRRef]
      ,[_Version]      
      ,[crt]
      ,[upd]
      ,[del]
      ,[cud]   -- 0 - created, 1 - updated, 2 - deleted
from TSource where [_Version] > @m)  
       AS Source (
       [_IDRRef]
      ,[_Version]      
      ,[crt]
      ,[upd]
      ,[del]
      ,[cud]
	   )  
ON  Target.[_IDRRef] = Source.[_IDRRef]




И вот далее я делаю MERGE

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
WHEN MATCHED and Target.[_Version] != Source.[_Version] 
THEN UPDATE SET upd = @ts, cud = 1


 
WHEN NOT MATCHED BY SOURCE	--отсутствуют в источнике, но есть в Target - помечаем как удаленные 
THEN UPDATE SET del = @ts, cud = 2

WHEN NOT MATCHED BY TARGET	--отсутствующие в Source, для получателя новые записи
THEN INSERT (
       [_IDRRef]
      ,[_Version]
      ,[crt]
      ,[cud]
	) VALUES (
       [_IDRRef]
      ,[_Version]
      ,@ts	-- as [crt]
      ,0	-- as [cud]
	  )  
OUTPUT $action INTO #t;  




Но вот одно НО

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
WHEN MATCHED and Target.[_Version] != Source.[_Version] 
THEN 
BEGIN 
     UPDATE SET upd = @ts, cud = 1
/*    INSERT (
       [_IDRRef]
      ,[_Version]
      ,[crt]
      ,[cud]
	) VALUES (
       [_IDRRef]
      ,[_Version]
      ,@ts	-- as [crt]
      ,0	-- as [cud]
	  ) */
 
WHEN NOT MATCHED BY SOURCE	--отсутствуют в источнике, но есть в Target - помечаем как удаленные 
THEN UPDATE SET del = @ts, cud = 2

WHEN NOT MATCHED BY TARGET	--отсутствующие в Source, для получателя новые записи
THEN INSERT (
...



по сути, мне нужно, при выполненном условии, где Target.[_IDRRef] = Source.[_IDRRef], но Target.[_Version] != Source.[_Version]
то нужно старую, существующую запись в target перевести в статус архива, но при этом сделать INSERT новой записи из Source

Однако я не могу сделать одновременно
WHEN MATCHED
UPDATE ...
INSERT ...

WHEN NOT MATCHED

Как решить такую задачу?
Спасибо
...
Рейтинг: 0 / 0
16.06.2021, 19:44
    #40078019
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Двоичник
мне нужно, при выполненном условии, где Target.[_IDRRef] = Source.[_IDRRef], но Target.[_Version] != Source.[_Version]
то нужно старую, существующую запись в target перевести в статус архива, но при этом сделать INSERT новой записи из Source
В MERGE переводить в архив, с помощью предложения output складывать нужные данные в буферную таблицу.
Затем из нее делать INSERT.
...
Рейтинг: 0 / 0
16.06.2021, 19:52
    #40078021
Двоичник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
invm,

Не понимаю как сделать вставку в буферную таблицу
DELETED.* - это то ,что я проапдейтил, увел в архив
INSERTED.* - это то что не сметчилось в мерже...

хм... хотя наверное я понял посыл.
нужно смотреть из DELETED.[_Version] != Source.[_Version]
но блин, это повторно собирать сканировать таблицу "Source". Как-то не феньшуйно...

В посте я перечислил мало полей, а по факту их порядка 80...
Буферную таблицу заполнять 80. полями... Это громоздко
...
Рейтинг: 0 / 0
16.06.2021, 19:56
    #40078023
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Моя задача далее сделать MERGE из каких соображений, если это решение не подходит? Напишите BEGIN TRAN UPDATE INSERT COMMIT и не майтесь.
...
Рейтинг: 0 / 0
16.06.2021, 20:54
    #40078039
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Двоичник,

Можно вот такой изврат попробовать
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
declare @t table (id int, v int)
insert into @t values
 (1, 1), (2, 1);

declare @s varchar(max) = '';

merge into @t t
using (values (1, 3), (2, 3)) s (id, v) on s.id = t.id
when matched and s.v <> t.v then
 update
  set
   v = s.v,
   @s += (select t.id as [@id], t.v as [@v] for xml path('matched_row'));

insert into @t
 (id, v)
 select
  b.n.value('@id', 'int'),
  b.n.value('@v', 'int')
 from
  (select cast(@s as xml)) a(x) cross apply
  a.x.nodes('matched_row') b(n);

select * from @t order by id, v;
...
Рейтинг: 0 / 0
17.06.2021, 11:48
    #40078226
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Двоичник

Однако я не могу сделать одновременно
WHEN MATCHED
UPDATE ...
INSERT ...

WHEN NOT MATCHED

Как решить такую задачу?
Спасибо



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
MERGE dbo.ИсторияПеремещенияСотрудниковПоДнямЛП_Таблица  AS target 
			USING (
				SELECT Дата									AS Дата,
					   Подразделение						AS Подразделение,
					   Сотрудник							AS Сотрудник,
					   Склад								AS Склад,
					   Должность							AS Должность,
					   1 									AS типВставки,
					   ДолжностьЛП							AS ДолжностьЛП
				FROM   ДляФильтрацииЗадвоенийПоДолжностям  
				WHERE  rn = 1 
			) AS source 
			ON	
				source.[Дата]		= target.[Дата]		AND
				source.[Склад]		= target.[Склад]	AND
				source.Сотрудник	= target.Сотрудник
			WHEN MATCHED AND (
			--  (target.Дата			<> source.Дата			 ) OR (target.Дата			IS NULL AND source.Дата				IS NOT NULL) OR (target.Дата			IS NOT NULL AND source.Дата				IS NULL) OR 
				(target.Подразделение	<> source.Подразделение	 ) OR (target.Подразделение	IS NULL AND source.Подразделение	IS NOT NULL) OR (target.Подразделение	IS NOT NULL AND source.Подразделение	IS NULL) OR 
			--  (target.Сотрудник		<> source.Сотрудник		 ) OR (target.Сотрудник		IS NULL AND source.Сотрудник		IS NOT NULL) OR (target.Сотрудник		IS NOT NULL AND source.Сотрудник		IS NULL) OR 
			--  (target.Склад			<> source.Склад			 ) OR (target.Склад			IS NULL AND source.Склад			IS NOT NULL) OR (target.Склад			IS NOT NULL AND source.Склад			IS NULL) OR 
				(target.Должность		<> source.Должность		 ) OR (target.Должность		IS NULL AND source.Должность		IS NOT NULL) OR (target.Должность		IS NOT NULL AND source.Должность		IS NULL) OR 
				(target.типВставки		<> source.типВставки	 ) OR (target.типВставки	IS NULL AND source.типВставки		IS NOT NULL) OR (target.типВставки		IS NOT NULL AND source.типВставки		IS NULL) OR 
				(target.ДолжностьЛП		<> source.ДолжностьЛП	 ) OR (target.ДолжностьЛП	IS NULL AND source.ДолжностьЛП		IS NOT NULL) OR (target.ДолжностьЛП		IS NOT NULL AND source.ДолжностьЛП		IS NULL) OR 
				1 = 0
			)
			THEN UPDATE SET 
			--  target.Дата				= source.Дата			,
				target.Подразделение	= source.Подразделение	,
			--  target.Сотрудник		= source.Сотрудник		,
			--  target.Склад			= source.Склад			,
				target.Должность		= source.Должность		,
				target.типВставки		= source.типВставки		,
				target.ДолжностьЛП		= source.ДолжностьЛП	
			WHEN NOT MATCHED BY TARGET THEN 
				INSERT (
					Дата,
					Подразделение,
					Сотрудник,
					Склад,
					Должность,
					типВставки,
					ДолжностьЛП
				)
				VALUES(
					Дата,
					Подразделение,
					Сотрудник,
					Склад,
					Должность,
					типВставки,
					ДолжностьЛП
				)

			;
...
Рейтинг: 0 / 0
17.06.2021, 11:53
    #40078229
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MERGE WHEN MATCHED UPDATE+INSERT
Насчет вот этого выражения:

Код: sql
1.
2.
(target.Должность		<> source.Должность		 ) OR (target.Должность		IS NULL AND source.Должность		IS NOT NULL) OR (target.Должность		IS NOT NULL AND source.Должность		IS NULL) OR 
				



1) Я прекрасно знаю о существовании ISNULL и осознанного его тут не использую
2) Если в таблице (запросе) много полей, то писать это выражение надо используя прямоугольное выделение блоков (в SSMS мышкой с нажатым ALT)
3) Если поле NOT NULL , то оптимизатор просто выкинет выражение Должность IS NOT NULL, что можно увидеть в актуальном плане
4) Запрос громоздкий, но быстрый и представляет собой одну транзакцию
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / MERGE WHEN MATCHED UPDATE+INSERT / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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