简体   繁体   中英

MariaDB get counted values grouped by datetime for all possible dates

1.48 table which looks like this:

CREATE TABLE `history` (
    `TIMESTAMP` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `DEVICE` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_bin',
    `TYPE` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_bin',
    `EVENT` VARCHAR(512) NULL DEFAULT NULL COLLATE 'utf8_bin',
    `READING` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_bin',
    `VALUE` VARCHAR(128) NULL DEFAULT NULL COLLATE 'utf8_bin',
    `UNIT` VARCHAR(32) NULL DEFAULT NULL COLLATE 'utf8_bin'
)
COLLATE='utf8_bin'
ENGINE=InnoDB
;

and some data which looks like this (only a small example of the available data)

INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-04 21:16:06', 'DL_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-04 22:31:09', 'CD_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-04 23:24:58', 'AB_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-05 00:25:58', 'XY_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-05 01:27:58', 'XY_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-05 02:27:58', 'DL_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');
INSERT INTO `history` (`TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT`) VALUES ('2023-01-05 02:29:02', 'DL_Motion', 'CUL_HM', 'state: motion', 'state', 'motion', '');

I want to have the amount of events grouped by date and hour for a dedicated device which works nice like this:

SELECT 
  DATE_FORMAT(TIMESTAMP,"%Y-%m-%d %H") AS ftimestamp,
  COUNT(TIMESTAMP) AS amount
FROM 
    history
WHERE  
  DEVICE = 'DL_Motion' 
  AND READING = 'state'
  AND VALUE = 'motion'
GROUP BY 
    YEAR(TIMESTAMP),MONTH(TIMESTAMP),DAY(TIMESTAMP),HOUR(TIMESTAMP); 

and comes to the result:

ftimestamp amount
2023-01-04 21 1
2023-01-05 02 2

For visualization purpose it would be great if I could get such a result:

ftimestamp amount
2023-01-04 21 1
2023-01-04 22 0
2023-01-04 23 0
2023-01-04 00 0
2023-01-04 01 0
2023-01-05 02 2

So all possible dates and hours where no data available shall have a zero.
There are enough data in the table to generate the list of all possible dates and hours with the following select:

SELECT
    DATE_FORMAT(TIMESTAMP,"%Y-%m-%d %H") AS ftimestamp
FROM
    history
GROUP BY
    YEAR(TIMESTAMP),MONTH(TIMESTAMP),DAY(TIMESTAMP),HOUR(TIMESTAMP);

I do not know how to combine this two request to come to the result I need.

If you have all dates available in the table, you can use conditional aggregation:

select date_format(timestamp, '%Y-%m-%d %H') as timestamp_hr,
    sum(device = 'DL_Motion' and reading = 'state' and value = 'motion') as amount
from history
group by date_format(timestamp, '%Y-%m-%d %H')

The logic is to scan the whole table so we do get all available dates, and then to count the relevant rows only, using the conditional sum() .

Note that I aligned the date expression in the select and group by clauses, which makes more sense in standard SQL.

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