【问题标题】:How can I Update a table changing only those rows which I want to change?如何更新仅更改我想要更改的行的表?
【发布时间】:2021-12-12 21:16:49
【问题描述】:

我有一张表,其中的状态应根据创建日期进行更改。 我尝试使用 DML 请求来实现这一点,但是通过这样的更新,所有行都会发生更改。 我怎样才能使我的代码更有效地只更改我在 CASE 中指出的那些行?

UPDATE your_day_test t
     SET t.status = CASE
                      WHEN t.create_date < trunc(SYSDATE - 28)
                           AND t.status = 1 THEN
                       -2
                      WHEN t.create_date < trunc(SYSDATE - 7)
                           AND t.status IN (0, 3) THEN
                       -1
                      WHEN t.create_date < trunc(SYSDATE - 42)
                           AND t.status = -2 THEN
                       -3
                      else
                         t.status
                    END
   WHERE trunc(t.create_date) > trunc(SYSDATE - 42)
   AND t.status IN (0, 1, 3, -2);
  COMMIT;

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    在 Oracle 中,您可以更新选择语句的结果,因此如果您可以编写一个仅选择您想要更新的行的选择,您可以这样做:

    update (
      select status, 
      CASE
          WHEN t.create_date < trunc(SYSDATE - 28)
              AND t.status = 1 THEN -2
          WHEN t.create_date < trunc(SYSDATE - 7)
              AND t.status IN (0, 3) THEN -1
          WHEN t.create_date < trunc(SYSDATE - 42)
              AND t.status = -2 THEN -3
      END new_status,
      create_date
      from your_day_test t
      WHERE trunc(t.create_date) > trunc(SYSDATE - 42)
        AND t.status IN (0, 1, 3, -2)
    ) set status = new_status
    where status <> new_status; -- assuming status is never null
    

    【讨论】:

    • 在Oracle 中可更新视图是有一定限制的,它很少可更新。见Notes on Updatable Views
    • @astentx 没有分组依据,没有分析函数,没有不同,your_day_test 可能是一个表 - 很有可能它可以更新。
    【解决方案2】:

    您正在使用日历日期检查 42 天范围内的 create_date,但在今天的日期之后过滤 where 子句中的 create_date。所以你只需要像下面这样更新你的 where 条件 -

    UPDATE your_day_test t
       SET t.status = CASE WHEN t.create_date < trunc(SYSDATE - 7) AND t.status IN (0, 3) 
                                THEN -1
                           WHEN t.create_date < trunc(SYSDATE - 28) AND t.status = 1 
                                THEN -2
                           WHEN t.create_date < trunc(SYSDATE - 42) AND t.status = -2 
                                THEN -3
                           ELSE t.status
                      END
     WHERE t.create_date < trunc(SYSDATE - 42)
       AND t.status IN (0, 1, 3, -2);
    

    【讨论】:

      【解决方案3】:

      您也可以在 where 子句中使用 case 语句。在这种情况下,您不需要 ELSE 子句:

      UPDATE your_day_test t
           SET t.status = CASE
                            WHEN t.create_date < trunc(SYSDATE - 28)
                                 AND t.status = 1 THEN
                             -2
                            WHEN t.create_date < trunc(SYSDATE - 7)
                                 AND t.status IN (0, 3) THEN
                             -1
                            WHEN t.create_date < trunc(SYSDATE - 42)
                                 AND t.status = -2 THEN
                             -3
                          END
         WHERE CASE
                            WHEN t.create_date < trunc(SYSDATE - 28)
                                 AND t.status = 1 THEN
                             -2
                            WHEN t.create_date < trunc(SYSDATE - 7)
                                 AND t.status IN (0, 3) THEN
                             -1
                            WHEN t.create_date < trunc(SYSDATE - 42)
                                 AND t.status = -2 THEN
                             -3
                            
                          END IN (-1,-2,-3);
      

      【讨论】:

        【解决方案4】:

        将另一个谓词添加到您的 where 条件中,过滤更新无效的行

           WHERE trunc(t.create_date) > trunc(SYSDATE - 42)
           AND t.status IN (0, 1, 3, -2)
           /* filter for real updates */
           AND t.status != CASE
                              WHEN t.create_date < trunc(SYSDATE - 28)
                                   AND t.status = 1 THEN
                               -2
                              WHEN t.create_date < trunc(SYSDATE - 7)
                                   AND t.status IN (0, 3) THEN
                               -1
                              WHEN t.create_date < trunc(SYSDATE - 42)
                                   AND t.status = -2 THEN
                               -3
                              else
                                 t.status
                            END
        

        另外,如果您厌倦每天更新表格(并且您不需要对更改后的status 列进行索引访问)-您可以生成新的仅在视图中显示状态。

        例子

        create or replace  view my_status as
        select
        STATUS as STATUS_ORIG,
        CREATE_DATE,
        CASE
         WHEN create_date < trunc(SYSDATE - 28)
              AND status = 1 THEN
          -2
         WHEN create_date < trunc(SYSDATE - 7)
              AND status IN (0, 3) THEN
          -1  
         WHEN create_date < trunc(SYSDATE - 42)
              AND status = -2 THEN
          -3
         else
            status
        END  as STATUS   
        from tab a; 
        

        【讨论】:

          猜你喜欢
          • 2015-08-10
          • 1970-01-01
          • 1970-01-01
          • 2019-05-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多