AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 116615
Accepted
Rainbolt
Rainbolt
Asked: 2015-10-01 07:38:21 +0800 CST2015-10-01 07:38:21 +0800 CST 2015-10-01 07:38:21 +0800 CST

如何避免在“匹配时更新”子句中重复相同的条件?

  • 772

我想将一个表合并到另一个表中。我需要在我的 WHEN MATCHED 子句中应用条件逻辑,理想情况下可以这样完成:

MERGE INTO ATable AS a
USING BTable AS b
ON a.ID = b.ID
WHEN NOT MATCHED THEN
-- Do insert
WHEN MATCHED AND b.NeedsAdjustment = 1 THEN
UPDATE SET
    Col1 = b.Col1 + b.Adjustment
    ,Col2 = b.Col2 + b.Adjustment
    ,Col3 = b.Col3 + b.Adjustment
WHEN MATCHED THEN -- Default case (b.NeedsAdjustment <> 1)
UPDATE SET
    Col1 = b.Col1
    ,Col2 = b.Col2
    ,Col3 = b.Col3

这不是有效的 SQL。根据 MSDN 文档:

如果有两个 WHEN MATCHED 子句,则一个必须指定一个 UPDATE 操作,一个必须指定一个 DELETE 操作。

这导致我进行以下查询:

MERGE INTO ATable AS a
USING BTable AS b
ON a.ID = b.ID
WHEN NOT MATCHED THEN
-- Insert happens here
WHEN MATCHED THEN
UPDATE SET
    Col1 = CASE WHEN b.NeedsAdjustment = 1 THEN b.Col1 ELSE b.Col1 + b.Adjustment END
    ,Col2 = CASE WHEN b.NeedsAdjustment = 1 THEN b.Col2 ELSE b.Col2 + b.Adjustment END
    ,Col3 = CASE WHEN b.NeedsAdjustment = 1 THEN b.Col3 ELSE b.Col3 + b.Adjustment END

条件逻辑被移动到更新内部,以绕过合并只能有一个WHEN MATCHED THEN UPDATE子句的事实。现在,我不是每行检查一次,而是每行每列检查一次(并且列比示例中的三列多得多)。

我可以避免对需要更新的每一列重复这种情况吗?有没有更好的方法来进行可能不涉及合并的条件更新?

sql-server update
  • 4 4 个回答
  • 1991 Views

4 个回答

  • Voted
  1. Zane
    2015-10-01T09:08:44+08:002015-10-01T09:08:44+08:00

    由于此处MERGE列出的所有原因,我建议首先避免使用,而只需使用标准更新语句。

    UPDATE A 
    SET
        Col1 = b.Col1 + b.Adjustment
        ,Col2 = b.Col2 + b.Adjustment
        ,Col3 = b.Col3 + b.Adjustment
    FROM ATable as A
    inner Join TableB as B
        ON a.ID = b.ID
        AND b.NeedsAdjustment = 1
    ;
    UPDATE A 
    SET
        Col1 = b.Col1 
        ,Col2 = b.Col2
        ,Col3 = b.Col3
    FROM ATable as A
    inner Join TableB as B
        ON a.ID = b.ID
    AND b.NeedsAdjustment <> 1
    --Or INSNUL(NeedsAdjustment,0) If it's a nullable column
    ;
    

    从长远来看,这将是一种比使用MERGE. 我还添加了,<>因为如果那不存在,您UPDATE将覆盖第一个UPDATE.

    • 7
  2. Best Answer
    Dave
    2015-10-01T08:57:02+08:002015-10-01T08:57:02+08:00

    MERGE是一个方便的陈述,但在这种情况下受到限制。我建议简单地分解您的查询,以便您可以完全涵盖您的逻辑。如果您期望或要求该MERGE语句将在单个事务中执行其操作,您可以围绕您的逻辑声明一个显式事务:

    BEGIN TRAN
    INSERT
    WHERE
    
    UPDATE
    WHERE
    
    UPDATE
    WHERE
    
    COMMIT TRAN
    
    • 4
  3. Andriy M
    2015-10-01T10:23:56+08:002015-10-01T10:23:56+08:00

    如果NeedsAdjustment是bit列,或者如果它是只能具有值 0 或 1 的整数列,那么您可以使用这样的单个 UPDATE 语句来涵盖这两种情况:

    UPDATE
      a
    SET
      a.Col1 = b.Col1 + b.NeedsAdjustment * b.Adjustment,
      a.Col2 = b.Col2 + b.NeedsAdjustment * b.Adjustment,
      a.Col3 = b.Col3 + b.NeedsAdjustment * b.Adjustment
    FROM
      dbo.ATable AS a
      INNER JOIN dbo.BTable AS b ON a.ID = b.ID
    ;
    

    如果该列可以为空,则另外应用 ISNULL 或 COALESCE:

    …
    SET
      a.Col1 = b.Col1 + ISNULL(b.NeedsAdjustment, 0) * b.Adjustment,
      a.Col2 = b.Col2 + ISNULL(b.NeedsAdjustment, 0) * b.Adjustment,
      a.Col3 = b.Col3 + ISNULL(b.NeedsAdjustment, 0) * b.Adjustment
    …
    
    • 4
  4. madreflection
    2015-10-01T10:52:45+08:002015-10-01T10:52:45+08:00

    使用 CTE,您可以“暂存”其中的数据,BTable以便您可以在 MERGE 语句中统一使用它。在这种情况下,如果一行不需要调整,请将调整更改为零。

    WITH b (Col1, Col2, Col3, Adjustment)
    AS
    (
        SELECT Col1, Col2, Col3, CASE WHEN NeedsAdjustment = 1 THEN Adjustment ELSE 0 END
        FROM BTable
    )
    MERGE INTO ATable AS a
    USING b
        ON a.ID = b.ID
    WHEN NOT MATCHED THEN
        -- Insert happens here
    WHEN MATCHED THEN
        UPDATE SET
            Col1 = b.Col1 + b.Adjustment,
            Col2 = b.Col2 + b.Adjustment,
            Col3 = b.Col3 + b.Adjustment;
    
    • 4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve