Including missing (zero counts) rows when using GROUP BY

I have an application that receives sms messages. What I want to do is make statistics with mysql, which will take meessages in an hour. For example, at 7 in the morning I received 10 SMS messages, at 8 in the morning I received 20, etc. My table has this column id, smsText, smsDate ... (others are not important). When I run this script:

SELECT HOUR(smsDate), COUNT(ID) FROM SMS_MESSAGES GROUP BY HOUR(smsDate)

It shows how many messages I receive every hour. The problem is that when I do not receive any message, for example, at 5 pm, this operator does not return line 17 with the number 0, and I have the result as follows:

Hour Count
...
15 10
16 5
18 2
...

and i want to get it

Hour Count
...
15 10
16 5
17 0
18 2
...

I was looking for a solution on the Internet, something with UNION, but I don’t understand how to implement it in mine. Hope someone can help me.

+4
3

:

CREATE TABLE IF NOT EXISTS `hours` (
  `hour` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `hours` (`hour`) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23);

SELECT hours.hour, count( SMS_MESSAGES.ID ) 
FROM hours
LEFT JOIN SMS_MESSAGES ON ( hours.hour = HOUR( SMS_MESSAGES.smsDate ) ) 
GROUP BY 1 
+3

hellocode , , , , union

select t.`hour`,count(s.ID) from (
select 0 as `hour`
union
select 1 as `hour`
union
select 2 as `hour`
union
.
.
.
select 23 as `hour`
) t
left join SMS_MESSAGES s on(t.`hour` = hour(s.smsDate))
group by t.`hour`
+2

: HOUR() . . .

, . .

: Heres , .

SELECT mintime + INTERVAL seq.seq HOUR AS msghour
  FROM (
        SELECT MIN(DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR) AS mintime,
               MAX(DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR) AS maxtime
          FROM SMS_MESSAGES
       ) AS minmax
  JOIN seq_0_to_999999 AS seq ON seq.seq < TIMESTAMPDIFF(HOUR,mintime,maxtime)

? .

: DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR . .

-, , (min max smsDate), .

-, seq_0_to_999999. : , . .

,

mintime + INTERVAL seq.seq HOUR AS msghour

, .

. , , . , :

 SELECT DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR, COUNT(ID)
   FROM SMS_MESSAGES 
   JOIN ( /*the query above wit the sequence of timestamps*/) AS sq 
     ON DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR = msghour
  GROUP BY DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR
  ORDER BY DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR

, :

 SELECT DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR, COUNT(ID)
   FROM SMS_MESSAGES 
   JOIN ( 
        SELECT mintime + INTERVAL seq.seq HOUR AS msghour
          FROM (
                SELECT MIN(DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR) AS mintime,
                       MAX(DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR) AS maxtime
                  FROM SMS_MESSAGES
               ) AS minmax
          JOIN seq_0_to_999999 AS seq ON seq.seq < TIMESTAMPDIFF(HOUR,mintime,maxtime)
       ) AS sq 
     ON DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR = msghour
  GROUP BY DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR
  ORDER BY DATE(smsDate) + INTERVAL HOUR(smsDate) HOUR

.

, seq_0_to_999999 ? , ? : ; arent MySQL ( MariaDB v10 + ).

. , , .

- 0 9, :

DROP TABLE IF EXISTS seq_0_to_9;
CREATE TABLE seq_0_to_9 AS
   SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
    UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9;

, , 1000 , :

DROP VIEW IF EXISTS seq_0_to_999;
CREATE VIEW seq_0_to_999 AS (
SELECT (a.seq + 10 * (b.seq + 10 * c.seq)) AS seq
  FROM seq_0_to_9 a
  JOIN seq_0_to_9 b
  JOIN seq_0_to_9 c
);

, 1000 , , , :

DROP VIEW IF EXISTS seq_0_to_999999;
CREATE VIEW seq_0_to_999999 AS (
SELECT (a.seq + (1000 * b.seq)) AS seq
  FROM seq_0_to_999 a
  JOIN seq_0_to_999 b
);

Here is a post that contains more information about all this. http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/

+1
source

Source: https://habr.com/ru/post/1545219/


All Articles