简体   繁体   中英

SQL Server count message per day

I'm using SQL Server and I have the following table:

tbl_Message:
id, date, group_id

Which is a table containing messages: it's id, the date it was sent, the group it was sent in. I'm trying to calculate the number of messages received every day. I made a query for it but it doesn't return days with no messages. The query is:

SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0) AS dateDay,
COUNT(*) AS countMsgDay
FROM tbl_Message
WHERE group_id = 1
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0)

Example:

For tbl_Message

id |     date                 | group_id
----------------------------------------
1  | 2014-10-01 21:04:00.000  | 1
2  | 2014-10-03 21:09:00.000  | 1

The query returns:

dateDay                    | countMsgDay
---------------------------------
2014-10-01 00:00:00.000    | 1
2014-10-03 00:00:00.000    | 1

and what I want is:

dateDay                    | countMsgDay
---------------------------------
2014-10-01 00:00:00.000    | 1
2014-10-02 00:00:00.000    | 0
2014-10-03 00:00:00.000    | 1

The normal solution to this problem is to generate all days of data and then use a left join . You can generate the days in several ways:

  • Using a calendar table.
  • Using recursive CTEs.
  • Using a numbers table.
  • Explicitly including the dates in the query.

In some cases, there is a simpler solution which is conditional aggregation. This assumes that there is at least one record for each day. Then, you can use conditional aggregation for this purpose:

SELECT CAST(date as DATE) as dateDay,
       SUM(CASE WHEN group_id = 1 THEN 1 ELSE 0 END) as countMsgDay
FROM tbl_Message
GROUP BY CAST(date as DATE)
ORDER BY dateDay;

This will work for you, assuming that each day has at least one record in the table .

Use this link to generate dates between your given dates. Use start_date as min(dateDay) and end_date as max(dateDay)

How to list all dates between two dates

Now use this table and join with your query. Say table to derive table is dateRange . So select * from dateRange will generate date from 2014-10-01 to 2014-10-03 .

Now use a query like below to get the desired output

select dr.dateval,t.countMsgDay
from dateRange dr
left join
(
    SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0) AS dateDay,
    COUNT(*) AS countMsgDay
    FROM tbl_Message
    WHERE group_id = 1
    GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0)
) t
on dr.dateval=t.dateDay

You will need a calendar table ,once you have that ,all you need to do is use left join with this table to get all dates.There are many use cases to calendar table other than this

EX:

select 
DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0) AS dateDay,
COUNT(*) AS countMsgDay
from 
Calendar c
left join
yourtable t
on t.date=c.date
and group_id = 1
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, date)/1440 * 1440,0)

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