0

我在尝试通过从另一个表格中选择日期作为条件来插入表格时遇到问题。日期将从另一个表而不是 Oracle 中检索,因为应用程序存储自己的系统日期(即今天可以是 10 年后的未来 - 20201124)。然后,日期的条件是 ASOF = TODAY-1 并且 DATE 在 TODAY 和 TODAY +1 之间。

这是我试图做的:

declare
   v_TODAY number;
begin 
   select TODAY into v_TODAY from LOCATION;
   execute immediate 'truncate table table_EOD';
   execute immediate 'insert into table_EOD (key1, key2, ASOF, IDATE)
   select key1, key2, ASOF, IDATE 
      from table
      where ASOF = to_char(to_date(v_TODAY)-1) 
      and DATE between v_TODAY and to_char(to_date(v_TODAY)+1)';
end;
/

我收到的错误是:

Error report:
ORA-00904: "V_TODAY": invalid identifier
ORA-06512: at line 6
00904. 00000 -  "%s: invalid identifier"

你能告诉我有什么问题吗?谢谢。

4

2 回答 2

1

您遇到的错误是正确的,它不是EXECUTE IMMEDIATE语句v_today范围内的有效标识符。您应该改用绑定变量

declare
   v_TODAY number;
begin 
   select TODAY into v_TODAY from LOCATION;
   execute immediate 'truncate table table_EOD';
   execute immediate 'insert into table_EOD (key1, key2, ASOF, IDATE)
   select key1, key2, ASOF, IDATE 
      from table
      where ASOF = to_char(to_date(:1)-1) 
      and DATE between :1 and to_char(to_date(:1)+1)'
     using v_today, v_today, v_today;
end;
/

还有两点。首先,如果您在 LOCATION 中有不止一行,那么您select into ...将无法正常工作。这是因为v_today只能保存一个值。将引发异常 TOO_MANY_ROWS;您将选择太多行!

其次,不需要第二个 EXECUTE IMMEDIATE。如果您引用的对象在编译块之前不存在,或者您正在动态生成 SQL,您只需在执行立即执行 DML。

您仍然需要执行truncate内部和 EXECUTE IMMEDIATE 语句,因为这是 DDL。这将为您留下以下内容:

declare
   v_TODAY number;
begin 

   select TODAY into v_TODAY from LOCATION; -- Still wrong!
   execute immediate 'truncate table table_EOD';

   insert into table_EOD (key1, key2, ASOF, IDATE)
   select key1, key2, ASOF, IDATE 
     from table
    where ASOF = to_char(to_date(v_TODAY)-1) 
      and DATE between v_TODAY and to_char(to_date(v_TODAY)+1);
end;
/

好的,从您的评论中,我刚刚意识到您实际上希望今天不是某个随机日期,并且您在 LOCATION 中使用数字作为日期,这是导致错误的原因。为什么不直接使用 Oracle 的 [ sysdate] 作为今天的日期?

declare
   v_TODAY date := sysdate;
begin 

   execute immediate 'truncate table table_EOD';

   insert into table_EOD (key1, key2, ASOF, IDATE)
   select key1, key2, ASOF, IDATE 
     from table
    where ASOF = trunc(sysdate) - 1
      and DATE between trunc(v_TODAY) and trunc(v_TODAY) + 1;
end;
/

如果您想使用自己的日期,则必须想办法在 LOCATION中放置日期而不是数字。

于 2012-11-15T08:49:18.743 回答
0

这里不需要 PL/SQL 或动态 SQL。

这样的事情应该这样做:

truncate table table_eod;

insert into table table_eod (key1, key2, asof, idate)
with today_data as (
   select today as v_today
   from location
)
select t.key1, t.key2, t.ASOF, t.IDATE 
from table t
  join today_data td on t.ASOF = to_char(to_date(td.v_TODAY)-1) 
      and DATE between td.v_TODAY and to_char(to_date(td.v_TODAY)+1);

我不确定如果表格LOCATION包含多于一行,这是否能正常工作。

于 2012-11-15T08:52:07.207 回答