简体   繁体   中英

Get amount of records with specific value, but only once per unique field

I'm not looking for a complete answer, but maybe some pointers as to what kind of mysql commands I should look at to figure this out.

I have a series of sensors (30+) connected to my network. At different intervals I request their status and each of the devices replies with n-amount of booleans, where n can be anything from zero to 120 (so the response can be an empty object, a list of 120 booleans, or any amount in between).

Per received boolean I create a new record, together with the device's mac address and a timestamp. For example ( see also this sqlfiddle ):

+----+-------------------+---------------------+--------+    
| id | device_address    | timestamp           | status |
+----+-------------------+---------------------+--------+    
|  1 | f2:49:d2:17:5d:8d | 2018-09-22 15:54:51 |      0 |
|  2 | fd:30:ec:08:67:9a | 2018-09-22 15:54:56 |      0 |
|  3 | f8:8d:d9:64:a4:7c | 2018-09-22 15:54:58 |      1 |
|  4 | f2:49:d2:17:5d:8d | 2018-09-22 15:55:51 |      0 |
|  5 | f2:49:d2:17:5d:8d | 2018-09-22 15:55:52 |      0 |
|  6 | fd:30:ec:08:67:9a | 2018-09-22 15:55:56 |      1 |
|  7 | f8:8d:d9:64:a4:7c | 2018-09-22 15:55:58 |      1 |
|  8 | f2:49:d2:17:5d:8d | 2018-09-22 15:56:52 |      0 |
|  9 | f2:49:d2:17:5d:8d | 2018-09-22 15:57:52 |      1 |
| 10 | f2:49:d2:17:5d:8d | 2018-09-22 15:58:52 |      1 |
+----+-------------------+---------------------+--------+

Or, with the mac address replaced for better readability:

+----+-------------------+---------------------+--------+    
| id | device_address    | timestamp           | status |
+----+-------------------+---------------------+--------+    
|  1 | A                 | 2018-09-22 15:54:51 |      0 |
|  2 | BB                | 2018-09-22 15:54:56 |      0 |
|  3 | CCC               | 2018-09-22 15:54:58 |      1 |
|  4 | A                 | 2018-09-22 15:55:51 |      0 |
|  5 | A                 | 2018-09-22 15:55:52 |      0 |
|  6 | BB                | 2018-09-22 15:55:56 |      1 |
|  7 | CCC               | 2018-09-22 15:55:58 |      1 |
|  8 | A                 | 2018-09-22 15:56:52 |      0 |
|  9 | A                 | 2018-09-22 15:57:52 |      1 |
| 10 | A                 | 2018-09-22 15:58:52 |      1 |
+----+-------------------+---------------------+--------+

In the end I want to be able to graph these values, grouped in intervals. For example, when I graph the last 2 hours worth of data, I want to use 5 minute intervals. Per interval I want to know how many (unique) devices had a status of 1 at least once in that period, and how many only had zeroes. Devices that don't appear within the timeblock at all (because they didn't return a boolean) are not relevant to that timeblock

The above records would fall within two of such 5 minute timeblocks:

  • 15:50:00 to 15:54:59 - ids 1 2 3
  • 15:55:00 to 15:59:59 - ids 4 5 6 7 8 9 10

The kind of response I'd like is something like this:

+---------------------+---------------------------------+-------------------------+    
| timeblock start     | dev w/ at least one status of 1 | dev w/ only status of 0 |
+---------------------+---------------------------------+-------------------------+    
| 2018-09-22 15:50:00 |                               1 |                       2 |
| 2018-09-22 15:55:00 |                               2 |                       1 |
+---------------------+---------------------------------+-------------------------+    

The final result does not have to be like this exactly, other results that can help me deduce these numbers would also work. The same is true for the timestamp field; this 2018-09-22 15:50:00 format would be great but other formats can also allow me to deduct what the timeblock was.

Doing something like this gets me the different timeblocks and the amount of unique devices within each timeblock, but it counts the total amount of 1s and 0s instead of combining the results of each unique device.

SELECT timestamp, 
SUM(status) as ones, COUNT(status)-SUM(status) as zeroes, 
COUNT(DISTINCT(device_address)) as unique_devices 
FROM records 
GROUP BY UNIX_TIMESTAMP(timestamp) DIV 300 
ORDER BY timestamp ASC

result:

+----------------------+------+--------+----------------+
| timestamp            | ones | zeroes | unique devices |
+----------------------+------+--------+----------------+
| 2018-09-22T15:54:51Z |    1 |      2 |              3 |
| 2018-09-22T15:57:52Z |    4 |      3 |              3 |
+----------------------+------+--------+----------------+

Use conditional aggregation

SELECT timestamp, 
       count(distinct case when status = 1 then device_address end) as ones, 
       count(distinct case when status = 0 then device_address end) as zeros, 
FROM records 
GROUP BY UNIX_TIMESTAMP(timestamp) DIV 300 
ORDER BY timestamp ASC

sqlfiddle demo

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