简体   繁体   中英

Oracle DB - Single query non-linear time grouping report (1 day, 1 week, 1 month, 3 months, total)

I'm trying to build a report that would essentially be a single query that combines the output of these queries:

select count(*) from my_table where createddate >= CURRENT_DATE - 1;
select count(*) from my_table where createddate >= CURRENT_DATE - 7;
select count(*) from my_table where createddate >= CURRENT_DATE - 30;
select count(*) from my_table where createddate >= CURRENT_DATE - 90;
select count(*) from my_table;

Such that the output would be similar to:

Time_Period   Count
===================
Yesterday        5
Last Week       20
Last Month      50
Last 90 Days   100
Total         5000

I've had success building several linear time series queries (by day, by week, by month, etc). But no luck in being able to build a non-linear reporting query.

You can put the results in separate columns easily:

select sum(case when createddate >= CURRENT_DATE - 1 then 1 else 0 end) as yesterday,
       sum(case when createddate >= CURRENT_DATE - 7 then 1 else 0 end) as last_week,
       sum(case when createddate >= CURRENT_DATE - 30 then 1 else 0 end) as last_month,
       sum(case when createddate >= CURRENT_DATE - 90 then 1 else 0 end) as last_90days,
       count(*) as total
from my_table;

If you want separate rows, you can unpivot the above, or just use union all :

select 'Yesterday' as which, count(*) from my_table where createddate >= CURRENT_DATE - 1
union all
select 'Last week', count(*) from my_table where createddate >= CURRENT_DATE - 7
union all
select 'Last month', count(*) from my_table where createddate >= CURRENT_DATE - 30
union all
select 'Last 90 days', count(*) from my_table where createddate >= CURRENT_DATE - 90
union all
select 'Total', count(*) from my_table;

You can put the offsets in rows with union all , then left join them with your table, like:

select
    o.time_period,
    count(t.created) cnt
from (
    select 'yesterday' time_period, 1 offs
    union all select 'last week', 7
    union all select 'last month', 30
    union all select 'last 90 days', 90
    union all select 'total', null
) o
left join mytable t on o.offs is null or t.created >= current_date - o.offs
group by o.time_period

One option would be using Dynamic Query in PL/SQL along with defining arrays for day periods and their literal explanations:

SQL> set serveroutput on
SQL> declare  
 v_sql    varchar2(250):='select count(*) from my_table where createddate >= current_date - :day'; 
 v_prd    owa.nc_arr;
 v_str    owa.vc_arr;   
 v_amount int;
begin
 v_prd(1) := 1;  v_prd(2) := 7; v_prd(3) := 30; v_prd(4) := 90; v_prd(5) := 100000;
 v_str(1) := 'Yesterday';  v_str(2) := 'Last Week'; v_str(3) := 'Last Month'; 
 v_str(4) := 'Last 90 Days'; v_str(5) := 'Total';   

     dbms_output.put_line('Time_Period   Count');
     dbms_output.put_line('===================');  
 for i in 1..5 
 loop
     execute immediate v_sql into v_amount using v_prd(i); 
     dbms_output.put_line(rpad(v_str(i),14,' ')||v_amount);  
 end loop;   
end;  
/

where v_prd(5) value could be as great as possible to contain all records of the table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM