【问题标题】:Postgres SQL UPDATE based on result of a previous SELECTPostgresql UPDATE 基于先前 SELECT 的结果
【发布时间】:2018-01-25 19:32:07
【问题描述】:

在 Postgres 10 中,我想执行两次 UPDATE。无论如何,第一个 UPDATE 都应该运行,更新alwaysupdate 列。只有当下面的 SELECT 语句返回的行数为 0 时,第二个 UPDATE 才应该运行,这意味着只有当 mytable 中的所有行都将 sometimesupdate 设置为 null 时,sometimesupdate 才应该更新。 .

-- Run no matter what, updating 'alwaysupdate'
update mytable set alwaysupdate = now() where keyA = 100 and keyB = 200

-- Check the number of rows where 'sometimesupdate' has a value
select count(*) from mytable where keyB = 200 and sometimesupdate is not null

-- If 'sometimesupdate' is null for all rows above, give it a value in this row
update mytable set sometimesupdate = now() where keyA = 100 and keyB = 200

最有效的方法是什么?是否可以将其组合成单个 SQL 语句?否则包含在事务中的多个语句?否则,必要时使用函数。

【问题讨论】:

    标签: sql postgresql sql-update


    【解决方案1】:

    一种方法将逻辑放在from 子句中:

    update mytable
        set alwaysupdate = now(),
            sometimesupdate = (case when b.cnt = 0 then now() else sometimesupdate end)
        from (select count(*) from mytable where keyB = 200 and sometimesupdate is not null
             ) b
        where keyA = 100 and keyB = 200;
    

    但是,not exists 通常性能更好:

    update mytable
        set alwaysupdate = now(),
            sometimesupdate = (case when not exists (select 1 from mytable where keyB = 200 and sometimesupdate is not null)
                                    then now()
                               end)
             ) b
        where keyA = 100 and keyB = 200;
    

    【讨论】:

    • 在您的第二个示例中,case 不需要像第一个示例中那样的else,还是没有它可以工作?当您设置sometimesupdate = sometimesupdate 时,Postgres 是否知道不更新表,因为实际上没有任何变化,或者在这种情况下修改触发器等仍然运行?
    • @user779159 。 . .不,不带else,值将设置为NULL——但由于查询的逻辑,我们知道值已经是NULL。我同意使用ELSE 子句使查询更清晰。
    【解决方案2】:

    试试这个

    如果 count 等于 0 则更新为 now() 否则保留有时更新的旧值

    update mytable as A
     set alwaysupdate = now(),
     sometimesupdate = (case when (
           select count(*) from mytable as B where B.keyB = A.keyB 
           and sometimesupdate is not null) = 0 
        then now() 
      else sometimesupdate end)
    where keyA = 100 and keyB = 200
    

    或者,如果您想更新没有有时更新且 keyb = 200 的特定行,请执行以下操作

    UPDATE mytable
    SET alwaysupdate = now(),
        sometimesupdate = (CASE
          WHEN keyB = 200 THEN CASE
              WHEN sometimesupdate IS NULL THEN now()
              ELSE sometimesupdate
            END
          ELSE sometimesupdate
        END)
    WHERE keyA = 100
    AND keyB = 200
    

    【讨论】:

      【解决方案3】:

      您可以使用链式 CTE,并以 EXISTS(...) [NOT EXISTS() 与 COUNT()==zero] 为条件进行第二次更新]


        -- Run no matter what, updating 'alwaysupdate'
      WITH u1 AS ( 
              UPDATE mytable 
              SET alwaysupdate = now() 
              WHERE keyA = 100 AND keyB = 200;
              RETURNING *
              )
      UPDATE mytable u2
      SET sometimesupdate = now() 
      FROM u1
      WHERE u1.keyA = u2.keyA -- 100
        AND u1.keyB = u2.keyB -- 200
              -- If 'sometimesupdate' is null for all rows below, give it a value in this row
              -- Check if there are any rows where 'sometimesupdate' has a value
      AND NOT EXISTS (SELECT * 
              FROM mytable nx
              WHERE nx.keyB = u2.keyB -- 200
              AND sometimesupdate IS NOT NULL
              );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-25
        • 1970-01-01
        • 1970-01-01
        • 2015-02-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多