繁体   English   中英

使用LAG()从自身进行SQL-Oracle更新表

[英]SQL-Oracle Update table from itself using LAG()

假设我们有一个像这样的表:

| Year | Month | Day | ID_Office | Operations | Operations yesterday |
|------|-------|-----|-----------|------------|----------------------|
| 2016 | 12    | 31  | 9555      | 500        | 0                    |
| 2017 | 1     | 1   | 9555      | 600        | 0                    |
| 2017 | 1     | 2   | 9555      | 750        | 0                    |
| 2017 | 1     | 3   | 9556      | 800        | 0                    |

我想使用上一行的“操作”更新“昨天的操作”中的值。 因此结果表必须是这样的:

| Year | Month | Day | ID_Office | Operations | Operations yesterday |
|------|-------|-----|-----------|------------|----------------------|
| 2016 | 12    | 31  | 9555      | 500        | 0                    |
| 2017 | 1     | 1   | 9555      | 600        | 500                  |
| 2017 | 1     | 2   | 9555      | 750        | 600                  |
| 2017 | 1     | 3   | 9556      | 800        | 0                    |

我将以下代码与函数LAG()配合使用,但未更新正确的值。

Update table1 F1
Set f1.operations_yesterday = 
                       (Select LAG(f1.operations, 1, 0) OVER(ORDER BY year, month, day)
                        From table1 F2
                        Where 
                        F1.year= F2.year And
                        F1.month= F2.month And
                        F1.day= F2.day);

您能从我的代码中给我一些关于到底是什么错误的建议吗? 在“插入到”语句中使用lag()函数取得了成功,但是在这种情况下,我必须提供Update语句解决方案。

注意:请注意,可能要订购三个以上的字段。 我仅以年,月和日为例,但是还有更多与日期无关的字段。 同样,重要的是要详细说明并非每天都有价值。

先感谢您!

一旦在子查询中传递了年,月和日的值,滞后函数将只有一行可用,该行将始终为您提供空值。 正确的方法应该是:

UPDATE table1 f1
   SET f1.operations_yesterday =
       (WITH table1_lag AS (SELECT ff.YEAR,
                                   ff.MONTH,
                                   ff.DAY,
                                   lag(ff.operations, 1, 0) over(ORDER BY ff.YEAR, ff.MONTH, ff.DAY) AS yesterday
                              FROM table1 ff)
           SELECT f2.yesterday
             FROM table1_lag f2
            WHERE f1.year = f2.year
              AND f1.month = f2.month
              AND f1.day = f2.day);

不建议冗余存储数据。 但是...

您想在记录中存储前一天的数据。 您假设每天都有一条记录,因此前一天也将是按日期排序之前记录 但是这些知识并没有真正的帮助,因为选择前一天比记录之前更容易。

分别存储日期,月份和年份而不是仅仅存储日期是很奇怪的。 我不知道您要达到什么目的。 我们将不得不笨拙地进行转换。

update table1 today
set operations_yesterday =
(
  select operations
  from table1 yesterday
  where to_date(yesterday.year * 10000 + yesterday.month * 100 + yesterday.day, 'yyyymmdd')
      = to_date(today.year * 10000 + today.month * 100 + today.day, 'yyyymmdd') - 1
);

如果您存储日期,那将是简单的:

update table1 today
set operations_yesterday =
      (select operations from table1 yesterday where yesterday.date = today.date - 1);

如果想要0而不是null(昨天没有),则添加COALESCE (或Oracle的NVL )。

如果缺少日期,并且您希望从前一天的值开始,那么可以使用merge

merge into table1 t1
using (select lag(operations, 1, 0) 
              over (partition by id_office order by year, month, day) lop
         from table1 t) t2
on (t1.rowid = t2.rowid)
when matched then update set operations_yesterday = t2.lop;

测试数据:

create table table1(Year number(4), Month number(2), Day number(2), 
    ID_Office number(5), Operations number(4), Operations_yesterday number(4));

insert into table1 values (2016, 12, 31, 9555, 500, null);
insert into table1 values (2017,  1,  1, 9555, 600, null);
insert into table1 values (2017,  1,  2, 9555, 750, null);
insert into table1 values (2017,  1,  3, 9556, 800, null);
insert into table1 values (2017,  1,  5, 9556, 400, null);

...并merge后:

 select * from table1;

 YEAR MONTH DAY ID_OFFICE OPERATIONS OPERATIONS_YESTERDAY
----- ----- --- --------- ---------- --------------------
 2016    12  31      9555        500                    0
 2017     1   1      9555        600                  500
 2017     1   2      9555        750                  600
 2017     1   3      9556        800                    0
 2017     1   5      9556        400                  800

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM