我的函数有问题。 我需要一张表格,其中包含一个月的日期、日期名称以及该月的工作日数量。 我已经在这里找到了一些帮助并根据我的需要进行了调整,但我无法运行/编译该函数 这是我到目前为止所拥有的:
create or replace TYPE DATE_ROW AS OBJECT
(
MyDate DATE,
Dayname VARCHAR2(12),
Amount Integer
)
create or replace TYPE DATE_TABLE as table of DATE_ROW
create or replace FUNCTION myfinaldays (mydate date)
RETURN DATE_TABLE
PIPELINED
IS
V_MYDATE DATE;
V_DAYNAME VARCHAR2(12);
V_AMOUNT NUMBER;
BEGIN
with this_month as (
select trunc(to_date('mydate'), 'mm')+level-1 dy
from dual
connect by level < (trunc(add_months(to_date('mydate'),1), 'mm')- trunc(to_date('mydate'), 'mm'))+1
)
FOR i IN 0 .. (select count(*) from this_month) LOOP
select (dy) Daydate,
to_char(dy, 'day'), Dayname,
( select count(*)
from this_month
where to_char(dy, 'dy') not in ('sat', 'sun')
) Amount
from this_month
where to_char(dy, 'dy') not in ('sat', 'sun')
and EXTRACT(day from to_date(dy)) = i;
pipe row (date_row(v_mydate,v_dayname, v_amount));
END LOOP;
RETURN;
END;
函数调用将类似于:
select * from date_table(cast(myfinaldays('01.02.12')));
我只能给出一个日期作为参数。
我希望有人可以帮助我,因为这慢慢让我发疯。 任何想法、例子或想法将不胜感激。
更新:
好的,这里是 mybe 的更新,对我的问题有一些更有用的信息:
这是有效的,我的目标是将其放入一个函数中,这样我就可以使用 1 个参数调用它:
with this_month as (
select trunc(to_date('01.02.12'), 'mm')+level-1 dy
from dual
connect by level < (trunc(add_months(to_date('01.02.12'),1), 'mm')- trunc(to_date('01.02.12'), 'mm'))+1
)
select (dy) mydate, (select count(*) from this_month) Days_in_month
, to_char(dy, 'day') Dayname
, ( select count(*) from this_month where to_char(dy, 'dy') not in ('sat', 'sun') ) Amount
from this_month
where to_char(dy, 'dy') not in ('sat', 'sun') ;
对于我在末尾添加的循环:“和 EXTRACT(day from to_date(dy))=i”。
我添加了一个日期,以便您可以看到我最终需要什么。如果我改为写 mydate 并在开发人员中运行后输入 01.02.12 作为参数,它仍然有效。
我编译时遇到的错误: - 错误(10,1):PL/SQL:忽略 SQL 语句
- Error(15,5): PL/SQL: ORA-00928: Keyword SELECT missing
- Error(22,8): PLS-00113: END-Definer 'LOOP' must complete 'myfinaldays' in row 1, comlumn 10
- Error(23,4): PLS-00103: Found the symbol "RETURN"
这些错误已被翻译,因为我的 Oracle 不运行英语,所以我希望猜对了。
最佳答案
您遇到了很多问题。
- 您不能直接在
for i in 1..x
中使用select
(它应该是 1,而不是 0),您必须选择到局部变量中并将其用作最终值。 - 您不能使用
with
作为for
循环的输入;但您可以在那里使用光标,如下所示。 - 当
i
代表星期六或星期日(本例中为第四个,假设您在二月份运行它)时,循环内的选择会出现 no-data-found。 - 获取每行的所有非周末行的计数效率很低,尽管对于如此少量的数据来说这并不重要。
- 您指的是
to_date('mydate')
; mydate 已经是一个日期,而 'mydate' 是一个与其无关的字符串。
也许还有其他一些事情,比如假设日期格式和区域设置,因为 to_char(x, 'dy')
不会返回 sat
或 sun
随处可见,但我假设这将以受限的方式使用,因此您不必太关心它。
通过尝试找出您期望的输出,我认为这会起作用(使用修改后的类型来获取您添加到原始问题中的days_in_month
):
create or replace type date_row as object
(
mydate DATE,
dayname VARCHAR2(12),
days_in_month NUMBER,
amount NUMBER
)
/
create or replace type date_table as table of date_row
/
create or replace function myfinaldays (mydate date)
return date_table pipelined deterministic is
begin
for r in (
select *
from (
select dy as daydate,
to_char(dy, 'day') as dayname,
count(*) over () as days_in_month,
sum(case when to_char(dy, 'dy') in ('sat', 'sun')
then 0 else 1 end) over () as amount
from (
select trunc(mydate, 'mm')+level-1 dy
from dual
connect by level < (trunc(add_months(mydate, 1), 'mm')
- trunc(mydate, 'mm')) + 1
)
)
where to_char(daydate, 'dy') not in ('sat', 'sun')
) loop
pipe row (date_row(r.daydate, r.dayname, r.days_in_month, r.amount));
end loop;
end myfinaldays;
/
(如果您不想days_in_month
,那么您可以移动sat
/sun
检查并使用count
表示 amount
而不是 sum(case)
。外部 select
目前正在按星期几进行过滤,以便您可以进行计数所有天,但如果您不想要该值,那不是问题)。
然后调用为:
alter session set nls_date_format = 'DD.MM.RR';
select * from table(myfinaldays(to_date('01.02.12', 'DD.MM.RR')));
MYDATE DAYNAME DAYS_IN_MONTH AMOUNT
-------- ------------ ------------- ----------
01.02.12 wednesday 29 21
02.02.12 thursday 29 21
03.02.12 friday 29 21
06.02.12 monday 29 21
...
29.02.12 wednesday 29 21
21 rows selected.
关于sql - 调用返回包含日期的表的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12600561/