将值放入不同日期范围的集合中

时间:2017-06-05 10:14:21

标签: oracle plsql

我正在编写一个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;

1 个答案:

答案 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;
/

虽然它只存储/显示计数,但没有说明它们属于哪个月,这可能最终不是你真正需要的。由于计数是有序的,你至少知道集合中的第一个元素代表一月,我想。