【问题标题】:Update based on same column基于同一列更新
【发布时间】:2020-05-31 23:46:14
【问题描述】:

我有一张这样的桌子:

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

我想用不同记录中分配的值替换空值。有没有办法在单个更新语句中做到这一点?

【问题讨论】:

    标签: sql postgresql group-by sql-update


    【解决方案1】:

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

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

    Demo on DB Fiddle:

    编号 |旗帜 -: | :--- 1 |吨 1 |吨 1 |吨 1 |吨 1 |吨 2 | F 2 | F 2 | F 2 | F 2 | F

    【讨论】:

      【解决方案2】:

      你也可以使用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))。

      【讨论】:

        【解决方案3】:

        提供的答案满足您的样本数据,但仍可能使您无法获得满意的答案。那是因为您的样本数据缺少几个重要的集合。如果您有以下内容,而不是当前的样本数据,或者除了您当前的样本数据之外,会发生什么情况?

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

        答案可能大不相同。

        【讨论】:

          【解决方案4】:

          假设(如您的示例数据所示):

          • 集合中的id 和true 和 false 永远不会有相同的id。否则,您必须定义要做什么。

          • 如果相同的id 没有非空值,null 的值将保持不变。

          这应该会给你最好的表现:

          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小提琴here

          子查询t1 提取每个 id 的目标值一次。

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

          由于null 排在最后,它有效地抓取每个id 的第一个非空值。 false 排在 true 之前,但这与案件无关,因为同一个 id 不可能同时存在。见:

          如果每个 id 有 很多 行,则有更快的技术:

          外部查询中添加的条件可防止发生所有无操作更新,从而避免重大成本。只有null 值实际发生变化的行才会更新。见:

          【讨论】:

            猜你喜欢
            • 2015-05-02
            • 1970-01-01
            • 2013-09-05
            • 1970-01-01
            • 1970-01-01
            • 2021-10-25
            • 1970-01-01
            • 2021-07-14
            • 2011-10-05
            相关资源
            最近更新 更多