用特定值更新多个行,用零更新其他行

时间:2019-05-20 17:37:07

标签: postgresql sql-update

如何有效地更新具有a_id 84特定值的多行,然后针对同一0将所有其他行设置为a_id

产品

p_id    a_id     best 
 111      81       99
 222      81       99
 666      82       99
 222      83       99  
 111      84       99       
 222      84       99
 333      84       99
 111      85       99  
 222      85       99       

现在我正在这样做:

SQL Fiddle

update products as u set
  best = u2.best
from (values
  (111, 84, 1),
  (222, 84, 2)
) as u2(p_id, a_id, best)
where u2.p_id = u.p_id AND u2.a_id = u.a_id
RETURNING u2.p_id, u2.a_id, u2.best

但这只会按预期更新values中的行。如何将values以外的行更新为0 = 84的a_id

意味着333的p_id应该具有best =0。我可以明确地包含每个p_id,但表很大。

  • 设置为best的值将始终按从1到 n 的顺序排列,由values的顺序定义。
  • products表具有一百万行

2 个答案:

答案 0 :(得分:1)

假设(p_id, a_id)是PK-或至少是UNIQUENOT NULL,这是一种方式:

UPDATE products AS u
SET    best = COALESCE(u2.best, 0)
FROM   products AS p
LEFT   JOIN ( VALUES
   (111, 84, 1),
   (222, 84, 2)
   ) AS u2(p_id, a_id, best) USING (p_id, a_id)
WHERE  u.a_id = 84
AND    u.a_id = p.p_id
AND    u.p_id = p.p_id 
RETURNING u2.p_id, u2.a_id, u2.best;

困难之处在于,FROM的{​​{1}}列表与UPDATE等效,而您需要INNER JOIN。此解决方法将表OUTER JOIN添加到products列表中(通常是多余的),以充当FROM的左表。 然后LEFT OUTER JOININNER JOIN的{​​{1}}起作用。

要另外限制products,请添加另一个products子句。这使a_id = 84表达式中的WHERE成为多余的,但是请保留在该表达式中以避免多个连接,这些连接只会在以后被过滤。便宜点。

如果没有PK列或任何其他a_id = 84列的组合,则可以退回到系统列VALUES来连接UNIQUE NOT NULL行。示例:

答案 1 :(得分:1)

从ON子句中删除条件u2.a_id = u.a_id,并使用CASE语句将其放在分配中:

update products as u set
  best = case when u2.a_id = u.a_id then u2.best else 0 end
from (values
  (111, 84, 1),
  (222, 84, 2)
) as u2(p_id, a_id, best)
where u2.p_id = u.p_id