基于同一列的sql更新

l0oc07j2  于 2021-08-13  发布在  Java
关注(0)|答案(4)|浏览(246)

我有一张这样的table:

ID | Flag
-----------
 1 | True
 1 | True
 1 | NULL
 1 | True
 1 | NULL
 2 | False
 2 | False
 2 | False
 2 | NULL
 2 | NULL

我想要这样的输出:

ID | Flag
-----------
 1 | True
 1 | True
 1 | True
 1 | True
 1 | True
 2 | False
 2 | False
 2 | False
 2 | False
 2 | False

我想用在不同记录中指定的值替换空值。有没有一种方法可以在一个update语句中实现呢?

5hcedyr0

5hcedyr01#

一个选项使用相关子查询:

update mytable t
set flag = (select bool_or(flag) from mytable t1 where t1.id = t.id)

db小提琴演示:

id | flag
-: | :---
 1 | t   
 1 | t   
 1 | t   
 1 | t   
 1 | t   
 2 | f   
 2 | f   
 2 | f   
 2 | f   
 2 | f
tzdcorbm

tzdcorbm2#

你也可以使用 exists :

update t
     set flag = exists (select 1 from t t2 where t2.id = t.id and t2.flag);

优势 exists 在具有聚合的子查询上是性能:查询可以在 flag 这是真的。这是对上的索引的简单索引查找 (id, flag) .
通过限制更新的行数,性能将得到更大的提高。这实际上意味着两种不同的说法:

update t
    set flag = true
    where (flag is null or not flag) and
          exists (select 1 from t t2 where t2.id = t.id and t2.flag);

update t
    set flag = false
    where (flag is null or flag) and
          not exists (select 1 from t t2 where t2.id = t.id and not t2.flag);

这些可以组合成一个(更复杂的)语句,但是被更新的集合是不相交的。这将限制对需要更新的行的更新,并将子查询限制为简单的查找(假设在 (id, flag) ).

nbnkbykc

nbnkbykc3#

所提供的答案满足您的样本数据,但仍可能使您缺少满意的答案。这是因为您的示例数据缺少几个重要集。如果您有以下数据,而不是当前的样本数据,或者除了当前的样本数据之外,会发生什么?

+----+-------+
| id | flag  |
+----+-------+
|  3 | true  |
|  3 | false |
|  3 | null  |
|  4 | null  |
|  4 | null  |
+----+-------+

答案可能大不相同。

mum43rcc

mum43rcc4#

假设(如您的样本数据所示):
不可能有相同的 idtruefalse 在片场。否则,你就得决定怎么做。 null 如果没有非空值,则值保持不变 id .
这将为您提供最佳性能:

UPDATE tbl t
SET    flag = t1.flag
FROM  (
   SELECT DISTINCT ON (id)
          id, flag
   FROM   tbl
   ORDER  BY id, flag
   ) t1                      -- avoid repeated computation for same id
WHERE  t.id = t1.id
AND    t.flag IS NULL        -- avoid costly no-op updates
AND    t1.flag IS NOT NULL;  -- avoid costly no-op updates;

db<>在这里摆弄
子查询 t1 提取每个id的目标值一次。

SELECT DISTINCT ON (id)
       id, flag
FROM   tbl
ORDER  BY id, flag;

null 最后排序,它有效地获取每个元素的第一个非空值 id . false 排序前 true 但这与案件无关,因为两者不可能同时存在 id . 请参见:
将空值排序到表的末尾
按组选择每组中的第一行?
如果每行有很多行 id ,有更快的技术:
按查询优化分组以检索每个用户的最新行
外部查询中添加的条件防止了所有no-op更新的发生,从而避免了主要的开销。只有在 null 价值实际上是变化的。请参见:
如何(或如何)在多个列上选择distinct?

相关问题