【问题标题】:Update to toggle a boolean column in a single statement更新以在单个语句中切换布尔列
【发布时间】:2019-03-22 01:08:42
【问题描述】:

如何以最有效的方式组合在单个 sql 语句中的两个查询?

UPDATE TABLE_A a
SET a.is_active = FALSE
WHERE a.id IN (SELECT id FROM TABLE_B);

同样,但切换其余ids的标志:

UPDATE TABLE_A a
SET a.is_active = TRUE
WHERE a.id NOT IN (SELECT id FROM TABLE_B);

【问题讨论】:

  • 您的第二个查询不会切换值,它只是将其设置为 true。

标签: sql postgresql performance query-optimization


【解决方案1】:

在 Postgres 中,您可以在 UPDATE 语句中使用 LEFT JOIN,语法如下:

UPDATE a 
SET a.is_active = CASE WHEN b.id IS NULL THEN FALSE ELSE TRUE
FROM TABLE_A a
LEFT JOIN TABLE_B b ON a.id = b.id

【讨论】:

    【解决方案2】:

    好吧,你可以使用CASE 表达式:

    UPDATE TABLE_A a
        SET a.is_active = (CASE WHEN a.id IN (SELECT id FROM TABLE_B)
                                THEN FALSE ELSE TRUE
                           END); 
    

    在 Postgres 中,您可以将其简化为:

    UPDATE TABLE_A
        SET is_active = (id IN (SELECT b.id FROM TABLE_B b));
    

    【讨论】:

      【解决方案3】:
      UPDATE table_a a
      SET    is_active = NOT EXISTS (SELECT FROM table_b b WHERE b.id = a.id);
      

      假设id 两个列都是NOT NULL

      否则,带有table_a.id IS NULL 的行在您的原始文件中完全未更新,因为NULL 既不是IN 也不是NOT IN 任何集合。

      如果table_b.id 中有任何NULLnone 您的行以a.is_active = TRUE 结尾,因为a.id NOT IN (SELECT id FROM TABLE_B)FALSENULL 但绝不是@ 987654336@ 在这种情况下。 NOT IN 因这种“陷阱”而臭名昭著。相关:

      这个带有EXISTS 的查询会更新所有行。 table_a.id IS NULL 的结果是 is_active = TRUE,就像在 table_b 中找不到的其他 ID 一样,table_b.id 中的 NULL 值没有任何区别。

      EXISTS 也很有吸引力,特别是如果table_b.id 中可以有(许多)重复值 - 更好的性能。 table_b.id 无论如何都应该被索引。

      【讨论】:

        【解决方案4】:

        您可以在两个表上使用连接,然后使用 case 语句来确定 TABLE B 中是否存在值:

        CREATE TABLE #TABLE_A (Id int, is_active bit)
        CREATE TABLE #TABLE_B (Id int)
        
        
        INSERT INTO #Table_A 
            VALUES   (1, NULL)
                    ,(2, NULL)
                    ,(3, NULL)
                    ,(4, NULL)
        
        INSERT INTO #TABLE_B 
            VALUES (1),(3)
        
        
        SELECT * FROM #TABLE_A
        
        UPDATE a
            SET is_active = (CASE WHEN b.id IS NULL THEN 1 ELSE 0 END)
        FROM    #TABLE_A a
                    LEFT OUTER JOIN #TABLE_B b
                        ON      a.id = b.Id
        
        SELECT * FROM #TABLE_A
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-25
          • 1970-01-01
          • 2014-08-19
          • 1970-01-01
          • 2019-10-03
          • 1970-01-01
          • 2014-05-04
          • 2017-09-27
          相关资源
          最近更新 更多