使用存储过程中的合并将表 A 中的许多行更新为表 B 中的几行

Posted

技术标签:

【中文标题】使用存储过程中的合并将表 A 中的许多行更新为表 B 中的几行【英文标题】:update many rows in Table A with few rows from Table B using merge on stored procedure 【发布时间】:2019-06-24 09:18:01 【问题描述】:

我在表 1 上有这样的数据:enter image description here

IdT1,IdT1Group

11 , 30

12、30

13 , 30

在表 2 上喜欢:enter image description here

IdT2、IdT1、详细信息、同步

1 , 11 , A , 插入

2、11、B、插入

3、12、A、插入

4、12、C、插入

我有这样的 tblSource:enter image description here

IdT2、IdT1、详细信息

1、11、A

2、11、B

5、11、C

我的 tblSource 来自:

Select Top 1 From Tbl2 where IdT1Group = 30

我希望我可以更新 Tbl2 成为:enter image description here

IdT2,   IdT1,   Detail, Synchronise

1       11        A     updated

2       11        B     updated

5       11        C     inserted

3       12        A     updated

4       12        B     updated

6       12        C     inserted

7       13        A     inserted

8       13        B     inserted

9       13        C     inserted

这是我用来获得预期结果的代码:

    Declare @IdT1Group integer = 30
;WITH tblTbl2
    AS (SELECT table2.* FROM table2 INNER JOIN table1 ON table2.IdT1 = table1.IdT1 AND IdT1Group = @IdT1Group)
    MERGE INTO tblTbl2 AS tblTarget
    USING (SELECT tblT2.*, table1.IdT1 AS T1Id FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group)
            AS tblSource ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
    WHEN MATCHED THEN
        UPDATE 
        SET     Detail = tblSource.Detail, Synchronise = 'updated'
    WHEN NOT MATCHED BY SOURCE THEN
        DELETE
    WHEN NOT MATCHED BY TARGET THEN            
        INSERT (IdT1, Detail, Synchronise)
        VALUES (tblSource.T1Id, tblSource.Detail, 'inserted');

但这就是我得到的:enter image description here

IdT2    IdT1    Detail  Synchronise
1       11        A     updated
2       11        B     updated
5       11        C     inserted
6       12        A     inserted
7       12        B     inserted
8       12        C     inserted
9       13        A     inserted
10      13        B     inserted
11      13        C     inserted

这个代码让我做一些试验:

drop table if exists table1
create table table1(idt1 int, idt1group int)

insert into table1 values (11,30),(12,30),(13,30)

drop table if exists table2

create table table2 (idt2 int, idt1 int, detail varchar(2), Synchronise varchar(15))

insert into table2 values (1,11,'A', 'Inserted'),(2,11,'B', 'Inserted'),
(3,12,'A', 'Inserted'),
(4,12,'B', 'Inserted')

drop table if exists tbl2

create table tbl2 (idt2 int, idt1 int, detail varchar(2), Synchronise varchar(15))
insert into tbl2 values (1, 11,'A', 'Inserted'), 
(2,11,'B', 'Inserted'), (5,11,'C', 'Inserted')

Declare @IdT1Group integer = 30

SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group

;WITH tblTbl2
    AS (SELECT table2.* FROM table2 INNER JOIN table1 ON table2.IdT1 = table1.IdT1 AND IdT1Group = @IdT1Group)
    MERGE INTO tblTbl2 AS tblTarget
    USING (SELECT tblT2.*, table1.IdT1 AS T1Id FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group)
            AS tblSource ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
    WHEN MATCHED THEN
        UPDATE 
        SET     Detail = tblSource.Detail, Synchronise = 'updated'
    WHEN NOT MATCHED BY SOURCE THEN
        DELETE
    WHEN NOT MATCHED BY TARGET THEN            
        INSERT (IdT1, Detail, Synchronise)
        VALUES (tblSource.T1Id, tblSource.Detail, 'inserted');

select * From Table2

【问题讨论】:

请不要以图片的形式提供数据,请以text 的形式提供。但是,我担心该数据对于您所说的 SQL Server 中的内容没有意义。一个值不能扩展到 SQL Server 中的多行,每一行都有它自己的值。请花时间删除图像并向我们提供您的数据的text 版本,甚至更好地作为 DDL 和 DML 语句。还包括您要实现的目标背后的逻辑;解释你的目标。我们很难在这里为您提供帮助,因为我们只有图像、无效数据和无效查询。谢谢。 好的,谢谢您的建议,因为我将实际数据更改为图像 【参考方案1】:

您正在删除给定数据

3       12        A     updated

4       12        B     updated

并且该数据不存在于

Declare @IdT1Group integer = 30

SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group

所以如果你仍然想更新它,那就是删除数据,然后你必须检查数据是否不存在然后更新它。

Declare @IdT1Group integer = 30

SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group


MERGE table2 AS tblTarget
--traget table 
USING 


--data src
(SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group)
AS tblSource ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
WHEN MATCHED THEN
UPDATE 
SET     Detail = tblSource.Detail, Synchronise = 'updated'

--Delete QUery
WHEN NOT MATCHED BY SOURCE THEN
DELETE

--insert query
WHEN NOT MATCHED BY TARGET THEN            
INSERT ([idt2],IdT1, Detail, Synchronise)
VALUES (tblSource.idt2,tblSource.T1Id, tblSource.Detail, 'inserted');

select * From Table2

如果您还有问题,请告诉我

【讨论】:

你能帮我实现我希望成为的样子吗? ==> i.stack.imgur.com/pxfgC.png【参考方案2】:

试试这个

--data query

drop table  table1
create table table1(idt1 int, idt1group int)

insert into table1 values (11,30),(12,30),(13,30)

drop table  table2

create table table2 (idt2 int, idt1 int, detail varchar(2), Synchronise varchar(15))

insert into table2 values (1,11,'A', 'Inserted'),(2,11,'B', 'Inserted'),
(3,12,'A', 'Inserted'),
(4,12,'B', 'Inserted')

drop table  tbl2

create table tbl2 (idt2 int, idt1 int, detail varchar(2), Synchronise varchar(15))
insert into tbl2 values (1, 11,'A', 'Inserted'), 
(2,11,'B', 'Inserted'), (5,11,'C', 'Inserted')


--main query

Declare @IdT1Group integer = 30

SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group

MERGE table2 AS tblTarget
--traget table 
USING 


--data src
(SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group)
AS tblSource ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
WHEN NOT MATCHED BY SOURCE THEN 
UPDATE 
SET   Synchronise = 'updated';



MERGE table2 AS tblTarget
--traget table 
USING 


--data src
(SELECT table1.IdT1 AS T1Id, tblT2.* FROM tbl2 AS tblT2 CROSS JOIN table1 where IdT1Group = @IdT1Group)
AS tblSource ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
WHEN MATCHED THEN
UPDATE 
SET     Detail = tblSource.Detail, Synchronise = 'updated'

--insert query
WHEN NOT MATCHED BY TARGET THEN            
INSERT ([idt2],IdT1, Detail, Synchronise)
VALUES (tblSource.idt2,tblSource.T1Id, tblSource.Detail, 'inserted');

select * From Table2

【讨论】:

抱歉,我在我的 Sql Server 上尝试过,但出现错误:Msg 8672, Level 16, State 1, Line 38 MERGE 语句多次尝试更新或删除同一行.当目标行匹配多个源行时会发生这种情况。 MERGE 语句不能多次 UPDATE/DELETE 目标表的同一行。优化 ON 子句以确保目标行最多匹配一个源行,或使用 GROUP BY 子句对源行进行分组。 您有重复记录请截断并查看

以上是关于使用存储过程中的合并将表 A 中的许多行更新为表 B 中的几行的主要内容,如果未能解决你的问题,请参考以下文章

使用雪花中的合并将值插入表并根据条件删除行

pl/sql 循环遍历表并将行的每个条目传递给存储过程

SQL 查询表中的更新行并将其插入为新行

存储过程:将表名转换为表变量

如何将列值从存储过程中的另一个表更新到表中?

sqlserver2005 表A跟存储过程B存在依赖关系,我为表A添加了一列C,修改存储过程B时报错说列C不存在。