【问题标题】:Add and / Or Updated Based on same table基于同一张表添加和/或更新
【发布时间】:2021-10-25 07:08:23
【问题描述】:

我有一个看起来像这样的表:

+--------+------+------------+
| ITEMNO | UNIT | CONVERSION |
+--------+------+------------+
| 123    | CTN  | 50         |
+--------+------+------------+
| 456    | CTN  | 300        |
+--------+------+------------+
| 789    | CTN  | 200        |
+--------+------+------------+

我想要的是有一个查询

A) 添加相同的 ITEMNO,其“UNIT”为“CT”,且 CONVERSION 与“CTN”相同

B) 如果 ITEMNO 已经有一个“CT”的“UNIT”,则使用与“CTN”相同的 CONVERSION 更新它

除了这两个“单位”之外,还有这些是我唯一需要玩的。

尝试将此作为更新,但没有奏效:(

update ICUNIT 
set ICUNIT.CONVERSION  = (
select CONVERSION from ICUNIT
where UNIT = 'CTN')
from ICUNIT
where UNIT = 'CT'

希望有人能帮忙!!

【问题讨论】:

  • 请不要添加问题的答案。在您决定MERGE 之前,请完整阅读this articlethis article - 我描述了一个更好的UPSERT 模式here。如果您要使用MERGE,请始终在目标上使用HOLDLOCK

标签: sql-server-2014


【解决方案1】:

正如评论中提到的,我建议避开MERGE。这些文章中有很多背景:

您需要同时执行INSERTUPDATE。这是两个需要在受保护事务中进行的操作,即使您使用像 MERGE 这样的语法糖,它看起来就像一个操作。

BEGIN TRANSACTION;

UPDATE trg WITH (UPDLOCK, SERIALIZABLE) 
  SET trg.CONVERSION = src.CONVERSION,
    ... other columns you want to match ...
FROM dbo.ICUNIT AS src
INNER JOIN dbo.ICUNIT AS trg
  ON src.ITEMNO = trg.ITEMNO
  WHERE src.CONVERSION = 'CTN'
    AND trg.CONVERSION = 'CT';

INSERT dbo.ICUNIT(ITEMNO, CONVERSION, ... other columns ...)
  SELECT ITEMNO, CONVERSION = 'CT', ... other columns ...
    FROM dbo.ICUNIT AS src
    WHERE src.CONVERSION = 'CTN'
      AND NOT EXISTS (SELECT 1 FROM dbo.ICUNIT AS trg
        WHERE trg.CONVERSION = 'CT' AND trg.ITEMNO = src.ITEMNO);

COMMIT TRANSACTION;

它比MERGE 多了几个字符,但避免了它的所有固有问题(我在Please stop using this UPSERT anti-pattern 中解释了更多)。如果您坚持使用MERGE,请,请,请您将HOLDLOCK 应用于目标表 - 如果您不这样做,那就是它背后的多个操作的事实真正开始解开。

无论如何,这似乎是一个奇怪的目标...如果您希望两行始终匹配除CONVERSION 以外的所有列,为什么还要设置两行?

【讨论】:

    【解决方案2】:

    听起来你想要MERGE

    WITH
      t AS (SELECT * FROM ICUNIT WHERE CONVERSION = 'CT' ),
      s AS (SELECT * FROM ICUNIT WHERE CONVERSION = 'CTN')
    MERGE t WITH (HOLDLOCK)
    USING s
    ON t.ITEMNO = s.ITEMNO
    WHEN MATCHED THEN
      UPDATE SET
        CONVERSION = s.CONVERSION,
        AUDTDATE = s.AUDTDATE,
        AUDTTIME = s.AUDTTIME,
        AUDTUSER = s.AUDTUSER,
        AUDTORG = s.AUDTORG
    WHEN NOT MATCHED THEN INSERT
      (ITEMNO, UNIT, CONVERSION,AUDTDATE,AUDTTIME,AUDTUSER,AUDTORG)
      VALUES
      (s.ITEMNO, 'CT', s.CONVERSION,s.AUDTDATE,s.AUDTTIME,s.AUDTUSER,s.AUDTORG);
    

    【讨论】:

    • 我已经添加到你的代码中,因为我刚刚意识到一些值是必需的,你能看看它是否有意义:)?
    • 我在下一节中添加了更多字段“当不匹配时插入(ITEMNO、UNIT、CONVERSION)如果您查看我的主要问题,我相信我只是想从原始 CTN 部分中提取以确保其正确
    • 不,您可能还想将其他字段添加到 UPDATE 部分(取决于您想要的结果)
    • 啊啊聪明!!,没想到!看起来不错,非常感谢!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    相关资源
    最近更新 更多