简体   繁体   中英

Is there a more efficient way to write SQL to group counts by date and column value

I have a status value of -1 or 1 stored in an H2 database at regular intervals and I need a count of how many -1's and 1's have been stored by month for the last 12 months. The following code works but I am going to use it as a derived table in multiple places and would like to know if there is a more efficient way of doing it.

SELECT  STATUS_CODE AS STATUS,
    COUNT(*) AS STATUS_COUNT,
    CASE    
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-1,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 1'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-2,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 2'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-3,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 3'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-4,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 4'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-5,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 5'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-6,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 6'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-7,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 7'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-8,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 8'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-9,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 9'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-10,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 10'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-11,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 11'
        WHEN EXTRACT(EPOCH FROM DATEADD(MONTH,-12,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME)   THEN 'MONTH 12'
        ELSE 'DONE' 
    END AS WEEK_RANGE
FROM    MY_TABLE 
WHERE   EXTRACT(EPOCH FROM DATEADD(MONTH,-12,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME) 
GROUP BY STATUS_CODE,  WEEK_RANGE
order by week_range

The results from running the previous code.

在此处输入图片说明

You could use DATEDIFF() to dynamically compute the difference between log_entry_time and the current date, in months:

SELECT  
    status_code AS status,
    COUNT(*) AS status_count,
    DATEDIFF(MONTH, log_entry_time, CURRENT_DATE) month_range
FROM MY_TABLE 
WHERE log_entry_time  >= DATEADD(MONTH, -12, CURRENT_DATE)
GROUP BY status_code, month_range
ORDER BY month_range

If LOG_ENTRY_TIME is of a date -like datatype, do not convert it to epoch for comparison, since doing so prevents the use of an index on that column. You can do date comparison instead, as show in the WHERE clause of the above query.

Would something like this be more useful?

SELECT  STATUS_CODE AS STATUS,
        COUNT(*) AS STATUS_COUNT,
        EXTRACT(YEAR FROM LOG_ENTRY_TIME) || '-' || EXTRACT(MONTH FROM LOG_ENTRY_TIME)
FROM    MY_TABLE 
WHERE   EXTRACT(EPOCH FROM DATEADD(MONTH,-12,CURRENT_DATE)) < EXTRACT(EPOCH FROM LOG_ENTRY_TIME) 
GROUP BY STATUS_CODE,  WEEK_RANGE
order by week_range;

This is a little different from what your query does, but this one provides actual month values (eg, "2019-12") for traceability rather than generic "Month N" labels. Even if not exactly what you're trying to achieve, perhaps this will give an idea.

(I'm not sure what an H2 equivalent of Oracle's TRUNC() is, but that would help gather data for full months rather than to the current day of a prior month; that's sort of what I was trying to achieve.)

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