Postgres SQL UPDATE基于前一个SELECT的结果

时间:2021-05-06 23:06:58

In Postgres 10 I want to perform an UPDATE twice. First UPDATE should run no matter what, updating the alwaysupdate column. And the second UPDATE should run only if the SELECT statement below returns a row count of 0, which means sometimesupdate should get updated only if all of the rows in mytable where mykey = 100 have sometimesupdate set to null.

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

-- 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

What's the most efficient way to do this? Is it possible to combine it into a single SQL statement? Otherwise multiple statements wrapped in a transaction? Otherwise a function if necessary.

最有效的方法是什么?是否可以将它组合成一个SQL语句?否则多个语句包含在一个事务中?如有必要,否则为其他功能

3 个解决方案

#1


1  

One method puts the logic in the from clause:

一种方法将逻辑放在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;

However, not exists would usually have better performance:

但是,不存在通常会有更好的性能:

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;

#2


1  

Try this

尝试这个

if count is equal to zero then update to now() otherwise retain the old value of sometimesupdate

如果count等于零,则更新到now()否则保留onceupdate的旧值

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

or if you want to update that specific row which has no sometimesupdate and is keyb = 200 then do below

或者如果你想更新那个没有有时更新并且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


1  

You can use a chained CTE, and make the second update conditional on an EXISTS(...) [NOT EXISTS() is the same as COUNT()==zero]

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


  -- 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
        );

#1


1  

One method puts the logic in the from clause:

一种方法将逻辑放在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;

However, not exists would usually have better performance:

但是,不存在通常会有更好的性能:

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;

#2


1  

Try this

尝试这个

if count is equal to zero then update to now() otherwise retain the old value of sometimesupdate

如果count等于零,则更新到now()否则保留onceupdate的旧值

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

or if you want to update that specific row which has no sometimesupdate and is keyb = 200 then do below

或者如果你想更新那个没有有时更新并且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


1  

You can use a chained CTE, and make the second update conditional on an EXISTS(...) [NOT EXISTS() is the same as COUNT()==zero]

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


  -- 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
        );