Oracle:接收ORA-06550和PLS-00905
题
我有一个包含数据的假日表
HOLIDAYDA DESCRIPTION
--------- --------------------
19-JAN-11 to
17-JAN-11 to
10-JAN-11 new day
现在,我想要一周的第一个工作日。即:如果我将“ 2011年1月12日”作为输入,我希望O/P作为2011年1月11日为第一个工作日,因为2011年10月10日是假期。
这是我的代码:
create or replace procedure sample as
l_dStartDay date;
l_dHolidayDate date;
begin
select trunc(to_date(sysdate),'Day')
into l_dStartday
from dual;
dbms_output.put_line('first day of the week ');
dbms_output.put_line(l_dStartDay);
for i in 2..5 Loop
select holidaydate
from holiday
into l_dHolidayDate
where holidaydate = (l_dStartDay + i);
if(l_dHolidaydate is null) then
dbms_output.put_line(l_dStartDay+i);
end if;
exit;
end loop;
end;
我编辑了上述程序,但使用编译错误创建的过程."
新添加:补充错误:
LINE/COL ERROR
-------- -----------------------------------------------------------------
9/1 PL/SQL: SQL Statement ignored
9/33 PL/SQL: ORA-00933: SQL command not properly ended
错误:
BEGIN sample; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object SYSTEM.SAMPLE is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
有人可以告诉我错误的原因吗?如果可能的话,告诉我解决方案?
解决方案
“我编译了上述程序,但
Procedure created with compilation errors
"
如果您使用的是IDE(例如TOAD或SQL开发人员),它将自动显示汇编错误。否则,使用此命令可以在SQL*Plus中访问它们:
SQL> show errors
还有一些视图,例如我们可以查询的user_errors。
问题很可能是选择语句,因为在投影后应立即遵循该条款:
select holidaydate
into l_dHolidayDate
from holiday
where holidaydate = l_dStartDay + i);
请注意,这看起来也错了:
select trunc(to_date(sysdate),'Day')
Sysdate已经是一个日期,尽管Oracle的最新版本倾向于在日期列上使用to_date更宽容。当从日期截断时间元素时,不必包括格式掩码,因为这是默认行为:
trunc(some_date_variable)
如果(说)我们想要一个月的第一天,我们只需要包括一个面具:
trunc(some_date_variable, 'MON')
如果您想找到一周的第一天,这将做到这一点:
SQL> select
2 trunc(to_date('01-DEC-2010', 'DD-MON-YYYY'), 'D') start_of_wk
3 from dual
4 /
START_OF_
---------
29-NOV-10
SQL>
请注意,一周的第一天取决于区域设置。在某些地区,一周的第一天是一个工作日(例如在英国的星期一),而不是(周日是美国第1天)。因此,可能有必要添加偏移。
一旦解决了汇编错误,您将发现SOEM运行时错误,可能与未经处理的NO_DATA_FOUND异常有关。这是因为您的查找查询在找不到匹配记录时不会返回null,它将失败。
这是一个简单的过程。它使用SQL解决方案,因为SQL是做事最有效的方法。内部查询使用trick连接的连接来生成结果集。然后,减去套件运算符将减少这一点,该操作员将过滤到该周范围内的任何假期。最后,外部查询返回查询的最早日期。
create or replace procedure get_first_working_day
( p_tgt_date in date )
is
l_st_day date := trunc(p_tgt_date, 'D');
l_working_day date := trunc(p_tgt_date, 'D');
begin
dbms_output.put_line('first day of week = '||l_st_day);
select min(day_of_wk)
into l_working_day
from ( select l_st_day + (level-1) as day_of_wk
from dual
connect by level <= 5
minus
select holidaydate
from hols
where holidaydate between l_st_day and l_st_day + 4 );
dbms_output.put_line('first working day of week = '||l_working_day
||'::'|| to_char(l_working_day, 'DAY'));
end get_first_working_day;
/
鉴于此测试数据(反映了英国银行假期的拜占庭状态)...
SQL> select holidate from hols
2 order by 1
3 /
HOLIDAYDA
---------
25-DEC-10
26-DEC-10
27-DEC-10
28-DEC-10
01-JAN-11
03-JAN-11
6 rows selected.
SQL>
...这是行动的过程:
SQL> set serveroutput on size unlimited
SQL>
SQL> exec get_first_working_day (sysdate)
first day of week = 10-JAN-11
first working day of week = 10-JAN-11::MONDAY
PL/SQL procedure successfully completed.
SQL>
SQL> exec get_first_working_day (to_date( '04-JAN-2011', 'DD-MON-YYYY'))
first day of week = 03-JAN-11
first working day of week = 04-JAN-11::TUESDAY
PL/SQL procedure successfully completed.
SQL>
SQL> exec get_first_working_day (to_date( '01-JAN-2011', 'DD-MON-YYYY'))
first day of week = 27-DEC-10
first working day of week = 29-DEC-10::WEDNESDAY
PL/SQL procedure successfully completed.
SQL>
顺便说一句,这是非常糟糕的做法:
PLS-00905: object SYSTEM.SAMPLE is invalid
不要将内置系统或系统帐户用于您自己的工作。有很大的机会打破一些东西。改为创建一个新的用户帐户。
其他提示
我猜那条线
where holidaydate = l_dStartDay + i);
错了,因为它有一个 )
它不应该在哪里。
除了已经提到的错误外,请尝试删除“退出”条款,因为此循环将迭代固定数量。另外,尝试在结束块时指定块名,如以下内容:
LOOP
...
END LOOP;
END ObjectName;
其中objectName是您的顶级程序。在这里,它将是“样本”,所以:
LOOP
...
END LOOP;
END sample;