【问题标题】:UPDATE 2 columns using MERGE having source conditions使用具有源条件的 MERGE 更新 2 列
【发布时间】:2017-11-21 09:27:47
【问题描述】:

SQL 服务器 2014

我需要用 SourceTable 中的值更新 TargetTable 中的两列

源表

PersonNr |   Block  |   BlockReason |
---------|----------|---------------|
000001   |   1      |   abuse       | 
000001   |   1      |   age         | 
000001   |   0      |   memo        | 
000002   |   1      |   age         | 
000002   |   0      |               | 
000003   |   0      |               | 
000003   |   0      |               | 
000004   |   1      |   behaviour   | 
000005   |   0      |               | 

目标表

PersonNr |   Block  |   BlockReason |
---------|----------|---------------|
000001   |   0      |               | 
000001   |   0      |               | 
000002   |   0      |               | 
000002   |   0      |               | 
000004   |   1      |               | 
000005   |   0      |               | 

需要结果:

PersonNr |   Block  |   BlockReason |
---------|----------|---------------|
000001   |   1      |   abuse       | 
000001   |   1      |   abuse       | 
000002   |   1      |   age         | 
000002   |   1      |   age         | 
000004   |   1      |   behaviour   |
000005   |   0      |               | 

BlockReason Person 1 得到哪个无关紧要, 至于它是来自Block = '1' 的行中的一个。

我已经尝试过这个非常简单的更新:

UPDATE
    src
SET
    src.Block = '1', 
    src.BlockReason = targ.BlockReason
FROM
    SourceTbl src
INNER JOIN
    TargetTable targ
ON 
    src.PersonNr= targ.PersonNr
WHERE src.Block = '1'

但最终出现了错误的结果行,其中 Block 和 Reason 分别更新:

PersonNr |   Block  |   BlockReason |
---------|----------|---------------|
000001   |  1       |   memo        | 

接下来我试过了:

MERGE INTO TargetTable AS TGT
USING
(
  SELECT Block, BlockReason, PersonNr
  FROM SourceTbl
 GROUP BY Block, BlockReason, PersonNr
) AS SRC
  ON 
    SRC.PersonNr= TGT.PersonNr AND 
    SRC.Block= '1' 
WHEN MATCHED THEN
UPDATE SET TGT.Block= SRC.Block, TGT.BlockReason= SRC.BlockReason;

得到错误

The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.

有什么帮助吗?非常感谢!真的。完全。

【问题讨论】:

  • 您的UPDATE 看起来一般正确,除了源和目标混淆。 (应该是目标,嗯,目标,但仍然是正确的咨询来源的块列)
  • @Kaptah 你的表的主键是什么?

标签: sql sql-server merge group-by


【解决方案1】:

您的查询的问题在于它提供了重复的值,并且它试图多次更新同一记录。并且子查询中的GROUP BY 没有任何意义,因为您没有使用任何聚合函数。

让我们获取一个 id(比如 1)并检查您的查询出了什么问题。

src.PersonNr |   src.Block  |   src.BlockReason | tgt.PersonNr |   tgt.Block  |   tgt.BlockReason |
-------------|--------------|-------------------|--------------
    000001   |   1          |   abuse           | 000001       |       0      |                   |         
    000001   |   1          |   age             | 000001       |       0      |                   | 
    000001   |   1          |   abuse           | 000001       |       0      |                   |
    000001   |   1          |   age             |  000001      |       0      |                   |

您的查询将为您提供上述结果,并尝试为每条记录更新 targettable 2 次,一次为滥用,下一次为年龄。

您可以尝试以下查询:

MERGE INTO TargetTable AS TGT
USING
(
 SELECT Block, BlockReason, PersonNr
 FROM(
       SELECT Block, BlockReason, PersonNr,ROW_NUMBER() OVER (PARTITION BY PersonNr  ORDER BY [YourPrimaryKey]) RN
       FROM SourceTbl ) X
 WHERE X.RN=1
) AS SRC
  ON 
    SRC.PersonNr= TGT.PersonNr AND 
    SRC.Block= '1' 
WHEN MATCHED THEN
UPDATE SET TGT.Block= SRC.Block, TGT.BlockReason= SRC.BlockReason;

【讨论】:

  • 经过更正尝试:FROM SourceTbl ) X WHERE X.RN=1。似乎工作:)
  • @Kaptah 对不起..这是一个错字..错过了WHERE。感谢您指出。更新了我的答案。
【解决方案2】:

UPDATE 应该是这样的:

UPDATE
    targ
SET
    Block = '1', 
    BlockReason = src.BlockReason
FROM
    SourceTbl src
INNER JOIN
    TargetTable targ
ON 
    src.PersonNr= targ.PersonNr
WHERE src.Block = '1'

由于我们只使用来自SourceTbl 的行,其中Block1,因此受此更新影响 的行应该不可能以一个原因结束Block0

SourceTbl 中的多行连接到TargetTbl 中的一行的情况下,仍然存在一个普遍的问题,但由于您已指出此处不需要确定性,因此它应该'不会导致问题。

【讨论】:

    【解决方案3】:

    您的数据中有重复项。在MERGEON 子句中添加另一个(或多个)列,这将有助于准确识别一条记录,或者找到一种方法在合并之前删除重复项。

    【讨论】:

      猜你喜欢
      • 2012-12-05
      • 2011-03-10
      • 2015-07-14
      • 1970-01-01
      • 2016-08-16
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多