使用存储过程中的合并将表 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 中的几行的主要内容,如果未能解决你的问题,请参考以下文章