Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 将MERGE语句的Update列作为其他表中的行进行审核_.net_Sql Server_Tsql_Merge_Audit - Fatal编程技术网

.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子句审核更改
我能够使用CASE语句执行以下操作:

| 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