.net 将MERGE语句的Update列作为其他表中的行进行审核
我正在努力实现以下目标.net 将MERGE语句的Update列作为其他表中的行进行审核,.net,sql-server,tsql,merge,audit,.net,Sql Server,Tsql,Merge,Audit,我正在努力实现以下目标 合并目标表和源表 使用output子句审核更改 我能够使用CASE语句执行以下操作: | Action | Record | ChangedFrom | ChangedTo | |----------|--------|-------------|-----------| | Inserted | 1 | NULL | 1 | | Deleted | 2 | 2 | NULL
- 合并目标表和源表
- 使用output子句审核更改
| Action | Record | ChangedFrom | ChangedTo |
|----------|--------|-------------|-----------|
| Inserted | 1 | NULL | 1 |
| Deleted | 2 | 2 | NULL |
| Action | Record | ChangedFrom | ChangedTo |
|---------|--------|--------------------|-------------------|
| UPDATED | 1 | ColA_Content_Before| ColA_Content_After|
- 审计插入和删除很容易
| Action | Record | ChangedFrom | ChangedTo |
|----------|--------|-------------|-----------|
| Inserted | 1 | NULL | 1 |
| Deleted | 2 | 2 | NULL |
| Action | Record | ChangedFrom | ChangedTo |
|---------|--------|--------------------|-------------------|
| UPDATED | 1 | ColA_Content_Before| ColA_Content_After|
我无法得到的:
| Action | Record | ChangedFrom | ChangedTo |
|----------|--------|-------------|-----------|
| Inserted | 1 | NULL | 1 |
| Deleted | 2 | 2 | NULL |
| Action | Record | ChangedFrom | ChangedTo |
|---------|--------|--------------------|-------------------|
| UPDATED | 1 | ColA_Content_Before| ColA_Content_After|
Merge语句将更改的值作为每行的列输出。我需要将这些列对更改为行,以便记录/行的每个更改列都成为审核表中的一个条目。
这里还有一些例子,因为我使用了3列,实际上,当我不知道列数是多少时,我需要它来工作 目标表 源表 合并结果
CREATE PROCEDURE MERGE_AUDIT
As
BEGIN
--Temporary TABLE variable to store the MERGE results
DECLARE @MERGERESULTS TABLE
(
[Action] nvarchar(50),
Id_After nvarchar(50),
ColA_After nvarchar(50),
ColB_After nvarchar(50),
ColC_After nvarchar(50),
ColD_After nvarchar(50),
UDate_After nvarchar(50),
Id_Before nvarchar(50),
ColA_Before nvarchar(50),
ColB_Before nvarchar(50),
ColC_Before nvarchar(50),
ColD_Before nvarchar(50),
UDate_Before nvarchar(50)
);
MERGE Test_Target as T
USING Test_Source as S
ON T.Id = S.Id
WHEN MATCHED AND
T.ColA <> S.ColA OR
T.ColB <> S.ColB OR
T.ColC <> S.ColC OR
T.ColD <> S.ColD OR
T.UDate <> S.UDate
THEN UPDATE SET
T.ColA = S.ColA ,
T.ColB = S.ColB ,
T.ColC = S.ColC ,
T.ColD = S.ColD ,
T.UDate = S.UDate
WHEN NOT MATCHED BY TARGET
THEN INSERT
(Id,ColA,ColB,ColC,ColD,UDate)
VALUES
(S.Id,S.ColA,S.ColB,S.ColC,S.ColD,S.UDate)
WHEN NOT MATCHED BY SOURCE
THEN DELETE
OUTPUT $action,Inserted.*,Deleted.* into @MERGERESULTS ;
-- Audit the Inserts
insert into [Audit]
(
ChangedFrom,
ChangedTo,
Action,
ChangedDate
)
select
Id_Before,
Id_After,
[Action],
GETDATE()
from @MERGERESULTS where [Action] = 'INSERT' ;
--Audit the DELETES
insert into [Audit]
(
ChangedFrom,
ChangedTo,
Action,
ChangedDate
)
select
Id_Before,
Id_After,
[Action],
GETDATE()
from @MERGERESULTS where [Action] = 'DELETE' ;
--unpivot to audit the UPDATES,
--USING REPLACE to remove the AFTER suffix when getting the column name
-- When storing the MERGE results in the TABLE variable having all columns as NVARCHAR is needed as to UNPIVOT the datataypes are needed to be same
insert into [Audit]
(
ChangedFrom,
ChangedTo,
Action,
ChangedDate,
[Column]
)
select * from (select
ChangedFrom,
ChangedTo,
[Action],
GETDATE() as ChangedDate,
REPLACE(p1col, '_After', '') as [Column]
from
(select
*
from @MERGERESULTS
UNPIVOT
(
ChangedFrom
FOR pcol IN (ColA_Before,ColB_Before,ColC_Before,ColD_Before)
) AS P
UNPIVOT
(
ChangedTo
For p1col IN (ColA_After,ColB_After,ColC_After,ColD_After )
) p1) as a
where
a.pcol = 'ColA_Before' and a.p1col = 'ColA_After' OR
a.pcol = 'ColB_Before' and a.p1col = 'ColB_After' OR
a.pcol = 'ColC_Before' and a.p1col = 'ColC_After' OR
a.pcol = 'ColD_Before' and a.p1col = 'ColD_After') as o -- this where condition is needed to get only relevant results, else we will get all the cols as it is a cross join
where o.ChangedFrom <> o.ChangedTo;
END
我需要这些列
| Action | Record | ChangedFrom | ChangedTo |
|--------:|--------|-------------|------------|
| Updated | 1 | Orig | Modified_A |
| Updated | 1 | Orig_B | MOdified_B |
我尝试过的方法:
| Action | Record | ChangedFrom | ChangedTo |
|----------|--------|-------------|-----------|
| Inserted | 1 | NULL | 1 |
| Deleted | 2 | 2 | NULL |
| Action | Record | ChangedFrom | ChangedTo |
|---------|--------|--------------------|-------------------|
| UPDATED | 1 | ColA_Content_Before| ColA_Content_After|
- 在proc中使用MERGE来执行批处理语句
- 在这里,我尝试使用游标遍历行,然后在case语句中插入col
- 使用动态sql和透视表
创建表[dbo]。[Test\u Source]
(
Id int不为空,
ColA VARCHAR(50)不为空,
ColB VARCHAR(50)不为空,
ColC VARCHAR(50)不为空,
ColD VARCHAR(50)不为空,
[UDate][DATETIME]不为空
)关于[初级];
去
创建表[dbo]。[Test_Target]
(
Id int不为空,
ColA VARCHAR(50)不为空,
ColB VARCHAR(50)不为空,
ColC VARCHAR(50)不为空,
ColD VARCHAR(50)不为空,
[UDate][DATETIME]不为空
)关于[初级];
去
---插入一些测试值
插入到[dbo]。[Test_Source]
(
Id,可乐,可乐,可乐,感冒,感冒
)
价值观
(
1、'ColA'、'ColB'、'ColC'、'ColD',GETDATE()
);
插入[dbo]。[Test_Target]
(
Id,可乐,可乐,可乐,感冒,感冒
)
价值观
(
1、'ColA_After'、'ColB_After'、'ColC_After'、'ColD_After',GETDATE()
);
创建过程合并测试
作为
开始
声明@MERGERESULTS表
(
[行动]nvarchar(50),
int之后的Id_,
nvarchar之后的可乐(50),
nvarchar(50)之后的ColB_,
nvarchar(50)之后的ColC_,
nvarchar(50)之后的冷_,
nvarchar(50)之后的UDate_,
int之前的Id_,
nvarchar之前的ColA_(50),
nvarchar之前的ColB_(50),
nvarchar(50)之前的ColC_,
nvarchar(50)前的冷态,
nvarchar之前的UDate_(50)
);
声明@AUDITRESULTS表
(
[行动]nvarchar(50),
int之后的Id_,
从nvarchar(50)更改,
更改为nvarchar(50)
);
声明
@作为NVARCHAR的cols(最大值),
@查询为NVARCHAR(最大值)
将测试对象合并为T
使用测试源作为
在T.Id=S.Id上
当匹配和
可乐
T.ColB S.ColB或
T.ColC S.ColC或
感冒
T.UDate S.UDate
然后更新集合
可乐,
T.ColB=S.ColB,
T.ColC=S.ColC,
T.ColD=S.ColD,
T.UDate=S.UDate
当目标不匹配时
然后插入
(身份证,可乐,可乐,可乐,感冒,感冒,乌拉特)
价值观
(S.Id,S.ColA,S.ColB,S.ColC,S.ColD,S.UDate)
当源不匹配时
然后删除
将$action、Inserted.*和Deleted.*输出到@MERGERESULTS;
从@MERGERESULTS中选择*;
从@MERGERESULTS中选择*进入#mytemp
--透视表的动态sql
选择@cols=STUFF((选择不同的“,”+QUOTENAME(可乐之后)
来自@MERGERESULTS
对于XML路径(“”),键入
).值('.',NVARCHAR(最大值)'
,1,1,'')
set@query='从#mytemp中选择*
支点
(
最大值(Id_后)
在('+@cols+'之后的ColA_)
)p'
选择@Cols作为“列”;
执行(@query)
--透视表的动态sql
--正在尝试游标和行计数(不完整)
--声明@Id int
--将行数设置为0
--挑选
--t、 行动,
--案例时间(t.ColA\u后t.ColA\u前)
--然后是t.ColA_
--完,,
--案例时间(t.ColA\u后t.ColA\u前)
--然后是t.ColA_
--完,,
--案例时间(t.ColB_后t.ColB_前)
--然后是t.ColB_
--完,,
--案例时间(t.ColB_后t.ColB_前)
--然后是t.ColB_
--完,,
--案例时间(t.ColC_后t.ColC_前)
--然后是t.ColC_
--完,,
--案例时间(t.ColC_后t.ColC_前)
--然后是t.ColC_
--完,,
--案例时间(t.ColD\u后t.ColD\u前)
--然后t.ColD_
--完,,
--案例时间(t.ColD\u后t.ColD\u前)
--那么,在你之前
--结束
--从#mytemp t
--内部连接#mytemp t1
--在t.Id_之后=t1.Id_之前
--在哪里
--t、 可乐在t1之后。可乐在t1之前
--t、 t1之后的ColB_。或之前的ColB_
--t、 t1之后的ColC_。或之前的ColC_
--t、 t1之后冷,t1之前冷
--将行数设置为1
--从#mytemp中选择@Id=Id#u
--而@@rowcount 0
--开始
--将行数设置为0
--(选择*from#mytemp,其中Id _After=@Id)
--删除#mytemp,其中au_id=@au_id
--将行数设置为1
--从mytemp中选择@au_id=au_id