“我编译了上面的程序,但是用
Procedure created with compilation
errors
”
如果您使用的是诸如 TOAD 或 SQL Developer 之类的 IDE,它会自动显示编译错误。否则,可以使用以下命令在 SQL*Plus 中访问它们:
SQL> show errors
还有诸如USER_ERRORS之类的视图我们可以查询。
问题很可能是 SELECT 语句,因为 INTO 子句应该紧跟在投影之后:
select holidaydate
into l_dHolidayDate
from holiday
where holidaydate = l_dStartDay + i);
请注意,这看起来也是错误的:
select trunc(to_date(sysdate),'Day')
SYSDATE 已经是一个 DATE,尽管较新的 Oracle 版本倾向于更宽容地在 DATE 列上使用 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>
请注意,一周的第一天取决于区域设置。在某些地区,一周的第一天是工作日(例如在英国的星期一),而在其他地区则不是(在美国,星期日是第一天)。所以可能需要添加一个偏移量。
解决编译错误后,您会发现一些运行时错误,可能与未处理的 NO_DATA_FOUND 异常有关。这是因为您的查找查询在找不到匹配记录时不会返回 NULL,它会失败。
这是一个简单的程序。它使用 SQL 解决方案,因为 SQL 是最有效的做事方式。内部查询使用 CONNECT BY 技巧来生成日期结果集。然后由 MINUS 集合运算符减少该值,该运算符将过滤掉该周范围内的任何假期。最后,外部查询返回查询的最早日期。
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
不要将内置的 SYS 或 SYSTEM 帐户用于您自己的工作。破坏东西的机会太大了。而是创建一个新的用户帐户。