我正在编写一个PL / SQL过程,它根据日期范围值给出查询计数。我想动态获取日期范围,并为此编写了一个光标。
我正在使用一个集合并获取每个月的计数,我面临的问题是集合上只填充了上个月的计数。我想得到所有月份的数量。有人可以帮忙吗?
这是我写的程序:
create or replace
Procedure Sample As
Cursor C1 Is
With T As (
select to_date('01-JAN-17') start_date,
Last_Day(Add_Months(Sysdate,-1)) end_date from dual
)
Select To_Char(Add_Months(Trunc(Start_Date,'mm'),Level - 1),'DD-MON-YY') St_Date,
to_char(add_months(trunc(start_date,'mm'),level),'DD-MON-YY') ed_date
From T
Connect By Trunc(End_Date,'mm') >= Add_Months(Trunc(Start_Date,'mm'),Level - 1);
Type T_count_Group_Id Is Table Of number;
V_count_Group_Id T_count_Group_Id;
Begin
For I In C1
Loop
Select Count(Distinct c1) bulk collect Into V_Count_Group_Id From T1
Where C2 Between I.St_Date And I.Ed_Date;
End Loop;
For J In V_Count_Group_Id.First..V_Count_Group_Id.Last
Loop
Dbms_Output.Put_Line(V_Count_Group_Id(J));
end loop;
END SAMPLE;
答案 0 :(得分:2)
您的bulk collect
查询每次都在循环中替换集合的内容;它不会附加到集合中(如果这是您所期望的)。因此,在循环之后,您只能看到上一个bulk collect
的结果,这是光标中的最后一个月。
您显然也将日期比较为字符串,这不是一个好主意(除非c2
存储为字符串 - 这更糟糕)。并且由于between
具有包容性,如果存储的时间部分是午夜,则您有可能将每月第一天的数据包括在两个计数中。对日期范围使用等式检查更安全。
您不需要使用游标来获取日期,然后使用该游标中的单个查询,您只需将当前游标查询加入目标表 - 使用外部联接可以允许几个月没有匹配的数据。您的光标似乎正在查找当年的所有月份,直到当年的开头,因此可能会简化为:
with t as (
select add_months(trunc(sysdate, 'YYYY'), level - 1) as st_date,
add_months(trunc(sysdate, 'YYYY'), level) as ed_date
from dual
connect by level < extract(month from sysdate)
)
select t.st_date, t.ed_date, count(distinct t1.c1)
from t
left join t1 on t1.c2 >= t.st_date and t1.c2 < t.ed_date
group by t.st_date, t.ed_date
order by t.st_date;
您可以使用它来填充您的收藏集:
declare
type t_count_group_id is table of number;
v_count_group_id t_count_group_id;
begin
with t as (
select add_months(trunc(sysdate, 'YYYY'), level - 1) as st_date,
add_months(trunc(sysdate, 'YYYY'), level) as ed_date
from dual
connect by level < extract(month from sysdate)
)
select count(distinct t1.c1)
bulk collect into v_count_group_id
from t
left join t1 on t1.c2 >= t.st_date and t1.c2 < t.ed_date
group by t.st_date, t.ed_date
order by t.st_date;
for j in v_count_group_id.first..v_count_group_id.last
loop
dbms_output.put_line(v_count_group_id(j));
end loop;
end;
/
虽然它只存储/显示计数,但没有说明它们属于哪个月,这可能最终不是你真正需要的。由于计数是有序的,你至少知道集合中的第一个元素代表一月,我想。