简体   繁体   中英

ORACLE Group query by week, month and year

I have a bunch of queries that take data with a time stamp and spit out SUMS based the last few weeks, months, and year to date. It looks like this

Week1    Sum for most recent week
Week2    Sum for second most recent week
WeekN    Sum for N most recent week
Jan-Dec  Sum for January-December
YTD      Sum for everything this year

This is how the query currently does this

SELECT TIME_PERIOD, INDEX, SUM(ITEM)   
FROM (SELECT
        INDEX ,
        (CASE  
            WHEN ACTIVITY_DAY>=(TO_DATE( :end_day,
            'yyyy-mm-dd' )-6)  
            AND ACTIVITY_DAY<=(TO_DATE( :end_day,
            'yyyy-mm-dd' )-0) THEN 'WEEK1'  
            WHEN ACTIVITY_DAY>=(TO_DATE( :end_day,
            'yyyy-mm-dd' )-13)  
            AND ACTIVITY_DAY<=(TO_DATE( :end_day,
            'yyyy-mm-dd' )-7) THEN 'WEEK2'  
            ELSE NULL  
        END) AS TIME_PERIOD,
        MAX(ITEMS) AS ITEM
    FROM
        SOURCE  
    GROUP BY
        INDEX ,
        DAY  
    UNION
    ALL SELECT
        INDEX ,
        (CASE  
            WHEN ACTIVITY_DAY>=TO_DATE( :year||'-01-01',
            'yyyy-mm-dd' )  
            AND ACTIVITY_DAY<=TO_DATE( :year||'-01-31',
            'yyyy-mm-dd' ) THEN 'Jan'  
            WHEN ACTIVITY_DAY>=TO_DATE( :year||'-02-01',
            'yyyy-mm-dd' )  
            AND ACTIVITY_DAY<TO_DATE( :year||'-03-01',
            'yyyy-mm-dd' ) THEN 'Feb'   
            ELSE NULL  
        END) AS TIME_PERIOD ,
        MAX(ITEMS) AS ITEM
    FROM
        SOURCE  
    GROUP BY
        INDEX ,
        DAY  
    UNION
    ALL SELECT
        INDEX ,
        (CASE  
            WHEN ACTIVITY_DAY>=TO_DATE( :year||'-01-01',
            'yyyy-mm-dd' )  
            AND ACTIVITY_DAY<=TO_DATE( :end_day,
            'yyyy-mm-dd' ) THEN 'YTD'  
            ELSE NULL  
        END) AS TIME_PERIOD,
        MAX(ITEMS) AS ITEM
    FROM
        SOURCE  
    GROUP BY
        INDEX ,
        DAY)
GROUP BY INDEX, TIME_PERIOD  

Is there a better way in Oracle?

I think you are looking for something like this:

with data as
(
    select sysdate - floor(dbms_random.value(1,400)) dt, floor(dbms_random.value(1,100)) val
    from dual
    connect by level <= 100
)
select
    time_period,
    sum(val) period_sum
from
(
    select -- weeks
        'Week'||(to_char(sysdate, 'WW') - to_char(dt, 'WW') + 1) time_period,
        val,
        (to_char(sysdate, 'WW') - to_char(dt, 'WW') + 1) ord
    from data
    where dt >= trunc(sysdate,'YY')
    union all
    select -- months
        to_char(dt, 'Mon') time_period,
        val,
        100+to_char(dt,'MM') ord
    from data
    where dt >= trunc(sysdate,'YY')
    union all
    select -- months
        'YTD' time_period,
        val,
        200
    from data
    where dt >= trunc(sysdate,'YY')
)
group by
    time_period, ord
order by
    ord;

Note that you won't need the WITH block, I was just using it to create some dummy data. The Ord column might be unnecessary for you, I was just using it to order the data in a logical fashion.

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