【问题标题】:Oracle procedure to increment dates增加日期的Oracle过程
【发布时间】:2020-01-24 22:53:14
【问题描述】:

我正在尝试根据条件增加日期(当日期大于另一个时):

CREATE OR REPLACE PROCEDURE schema.procedura
 AS

dt_lst DATE;
dt_md  DATE;
eu_val INT;

BEGIN

  for i in (select rowid, TABLELORIK.* from TABLELORIK)

LOOP

   dt_md  := to_date('20290401','YYYYMMDD');
   dt_lst := to_date('20190802','YYYYMMDD');
   eu_val := 180

 while  dt_md > dt_lst 
  LOOP
   dt_lst := dt_lst + eu_val;
  END LOOP;

  UPDATE TABLELORIK set DATE_COL = to_char(dt_lst,'YYYYMMDD') where rowid=i.rowid;
  COMMIT;

END LOOP;
END procedura;
/

在这种情况下,我想要的输出是 DATE_COL = 20281212(实际上它比 dt_md 小,循环应该停在那里!)

在这种情况下,我的循环输出是什么:20290610(额外的 +180 天(一个循环步骤,现在条件 dt_md > dt_lst 已损坏))

有人可以帮我完成最后一步以停止循环而不通过 dt_md。

【问题讨论】:

  • 为什么要循环执行此操作?还是完全使用 PL/SQL? (为什么要将日期存储为字符串!?)
  • 快速修复是... WHILE dt_md > dt_lst + eu_val LOOP ...。但我认为这不需要任何缓慢的程序部分。
  • 不需要循环或过程,计算简单:dt_lst + trunc((dt_md-dt_lst) / 180) * 180
  • 你到底为什么将DATE 值存储为s 字符串(或数字)?不要那样做,将列 DATE_COL 转换为正确的 DATE 数据类型。
  • 正如其他人已经说过的那样,不需要循环。除此之外,当您使用WHERE ROWID = ... 时,您应该使用FOR UPDATE 锁定记录,否则ROWID 可能会更改。见stackoverflow.com/questions/49110728/where-current-of-in-pl-sql/…

标签: sql oracle plsql


【解决方案1】:

您的代码中不需要任何循环,也不需要使用 PL/SQL。

您可以直接计算目标日期:

select to_date('20190802','YYYYMMDD')
  + 180 * trunc((to_date('20290401','YYYYMMDD') - to_date('20190802','YYYYMMDD'))/180)
from dual;

TO_DATE('2
----------
2028-12-12

或使用日期文字:

select date '2019-08-02' + 180 * trunc((date '2029-04-01' - date '2019-08-02')/180)
from dual;

两个日期之间的差是一个数字或天数。 date '2029-04-01' - date '2019-08-02' 给你 3530。你想知道有多少个 180 的完整倍数适合它,所以除以 180,得到 19.6111...;将其截断为 19;再乘以 180 得到你想要的实际天数,3420;最后将其添加回您的开始日期。

然后一次更新表中的所有行:

update TABLELORIK
set date_col = date '2019-08-02' + 180 * trunc((date '2029-04-01' - date '2019-08-02')/180);

如果您的列确实是一个字符串,则将其包装在 to_char() 中,但您不应该将日期存储为字符串。

你可以把它变成一个程序,但似乎没有多大意义。

即使这是在循环中递增的赋值,您也不需要逐一更新表中的每一行;并且不需要每次都重新计算dt_lst(除非赋值实际上是调整原始列值,而不是全部调整到同一个固定日期):

CREATE OR REPLACE PROCEDURE procedura
AS

  dt_lst DATE;
  dt_md  DATE;
  eu_val INTEGER;

BEGIN

  dt_md  := date '2029-04-01';
  dt_lst := date '2019-08-02';
  eu_val := 180;

  while dt_lst + eu_val <= dt_md
  LOOP
    dt_lst := dt_lst + eu_val;
  END LOOP;

  UPDATE TABLELORIK set DATE_COL = dt_lst;

END procedura;
/

insert into TABLELORIK (id, date_col) values (1, sysdate);
insert into TABLELORIK (id, date_col) values (2, null);

exec procedura;

select * from TABLELORIK;

        ID DATE_COL  
---------- ----------
         1 2028-12-12
         2 2028-12-12

【讨论】:

    【解决方案2】:

    如果你想让你的while 循环退出之前 dt_lst 大于dt_md,你必须这样说。试试这个:

    while dt_md > dt_lst + eu_val
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 2023-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多