One would think this is simple, but has been kicking by butt all night. I have a log of sensor alerts and want to generate a table with simple counts of events that fall within 24hrs, 168hrs (1 wk), and 336hrs (2 wks) for each distinct sensor. I'm relatively new and self-taught at MySQL (running on GoDaddy) and have tried every variation of Count, Unique, Case, etc. that I found on the web. Help me Obi Wan...
Sample Data:
Alert_timestamp
SensorID
2022-05-18 21:41:59
Sensor 1
2022-05-21 21:52:09
Sensor 1
2022-05-24 05:00:39
Sensor 2
2022-05-24 05:02:26
Sensor 1
2022-05-24 18:37:34
Sensor 4
2022-05-24 20:48:40
Sensor 1
2022-05-26 21:20:54
Sensor 2
2022-05-27 14:53:02
Sensor 1
2022-06-01 19:06:14
Sensor 4
2022-06-02 19:22:27
Sensor 1
...
...
Desired Output (note: counts below don't correspond to table above). Even if a sensor has zero alerts (e.g. sensor exists in the table, but no events inside the date rage), i want to see those too.
count of events that fall within these ranges
Sensor
<24hrs
24 to 168hrs
168 to 336hrs
Sensor 1
1
1
0
Sensor 2
0
2
5
Sensor 3
0
0
0
Sensor 4
6
2
3
Thanks ahead of time!
Use conditional aggregation.
SELECT SensorID,
SUM( Alert_timestamp > CURRENT_TIMESTAMP - INTERVAL 24 HOUR) `<24hrs`,
SUM( Alert_timestamp <= CURRENT_TIMESTAMP - INTERVAL 24 HOUR
AND Alert_timestamp > CURRENT_TIMESTAMP - INTERVAL 168 HOUR) `24 to 168hrs`,
SUM( Alert_timestamp <= CURRENT_TIMESTAMP - INTERVAL 168 HOUR
AND Alert_timestamp > CURRENT_TIMESTAMP - INTERVAL 336 HOUR) `168 to 336hrs`
FROM table
WHERE Alert_timestamp > CURRENT_TIMESTAMP - INTERVAL 336 HOUR
GROUP BY SensorID
If the table contains the rows "in future" then add according conditions to the first aggregation and to WHERE.
The index by (SensorID, Alert_timestamp) will improve.
Related
I'm measuring different kind of events daily and get records looking like that:
id measurement_date value
111 2020-12-01 21:30:00 100
111 2020-12-02 22:00:12 110
111 2020-12-03 21:35:17 80
114 2020-12-02 21:47:56 780
114 2020-12-04 21:55:47 700
....
Then I am having a query transforming the data to get the difference between 2 measurements.
I am running this transform on different windows of time (1 day, 7 days, 1 month).
For 1 day it is quite straightforward as I either have a measurement or if missing I have no intermediary data to compensate and therefore place a 0.
Here is the query I use:
SELECT id,
(ft.value - ft2.value) as progression,
FROM feed_table ft
JOIN feed_table ft2 on ft2.id = ft.id
AND date_format(ft2.date, '%Y-%m-%d') = date_format(date_sub(CURDATE(), interval 1 day), '%Y-%m-%d')
WHERE date_format(ft.date, '%Y-%m-%d') = date_format(CURDATE(), '%Y-%m-%d')
However for longer windows, like 7 days, for example, I would like to make use of the intermediary data if they exist.
Let's say I am measuring on the 7 days window between today 2020-12-08 and 7 days before 2020-12-01, but I only have the following measurements which are neither today nor 7 days ago but are still inside the 7 days window:
id measurement_date value
111 2020-12-02 21:30:00 200
111 2020-12-06 21:30:00 300
Then the query above with a 7D interval and the right settings should return :
id progression
111 100
(max date value - min date value in the 7 days window)
I was thinking of aggregating by user_id and using the min-max date in the having close, but my self-join wouldn't work anymore...
Any idea?
I have a number of records in a MySQL database with one of the fields which tracks the time of the record creation. It is of the type 'timestamp' with the default set to CURRENT_TIMESTAMP. I am trying to access all records that are newer than 5 minutes old. I have used the following query in a PHP page:
SELECT username FROM liveusers WHERE timejoined < NOW() - INTERVAL 5 MINUTE)
For some reason, it doesn't select any records and I'm not sure how to rectify it. The PHP code is fine as it selects all records if I remove the condition. What am I doing wrong?
I suggest you to use DATE_SUB:
SELECT username FROM liveusers WHERE timejoined > DATE_SUB(NOW(),INTERVAL 5 MINUTE);
https://www.w3schools.com/sql/func_mysql_date_sub.asp
You were doing the comparison the other way arround. Newer records should have a greater date than 5 minutes ago.
First, you are comparing a timestamp against a date. You want to do first a conversion of the date, in example, using UNIX_TIMESTAMP()
5 minutes is 300 seconds. Let's imagine someone joined at 50 and NOW() is 301 (it should be "newer"). WHERE timejoined < UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE) will become -> WHERE 50 < 301 - 300 <- false
You want to write :
WHERE timejoined > UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE)
Schema (MySQL v5.7)
Query #1
SELECT UNIX_TIMESTAMP(NOW() - INTERVAL 4 MINUTE) > UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE) AS "is 4 minutes ago \"newer\" ?";
| is 4 minutes ago "newer" ? |
| -------------------------- |
| 1 |
Query #2
SELECT UNIX_TIMESTAMP(NOW() - INTERVAL 6 MINUTE) > UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE) AS "is 6 minutes ago \"newer\" ?";
| is 6 minutes ago "newer" ? |
| -------------------------- |
| 0 |
View on DB Fiddle
I have a table t_windows_updates which has two columns ci_id and update_installed_on. Table will be having all the windows updates happened to all the assets in my environment.
Data will be like
ci_id| update_installed_on
1 | 1452364200000
1 | 1453055400000
2 | 1441650600000
2 | 1441650600000
2 | 1441650600000
I want to get all ci_ids for which the latest update didn't happen in the last six months.
My Query is
SELECT t.ci_id FROM `t_windows_update` t
GROUP BY t.ci_id
HAVING MAX(t.update_installed_on)<= (NOW() - INTERVAL 6 MONTH);
It is running but getting wrong results.
Your problem is the date format.
I think this is a unix format in milliseconds. So, this suggests something like:
having max(t.update_installed_on) <= UNIT_TIMESTAMP(CURDATE() - INTERVAL 6 MONTH) * 1000
I realize that the above could have overflow issues with integers, so let's go the other way:
having max(t.update_installed_on) / 1000 <= UNIT_TIMESTAMP(CURDATE() - INTERVAL 6 MONTH)
So my coworker is looking at a schema which could be described as something like this:
+--------------------+-----------+
| DATETIME timestamp | INT value |
+--------------------+-----------+
Every 5 minutes a row is entered with the value for that moment.
Here's where it gets tricky. He wants to get the average of every 8 hour period within a 7 day interval.
Certainly, I can think of solutions which involve some client side code, we were wondering if it was possible to do more in SQL.
So in essence, he wants:
SELECT timestamp, value
FROM table
WHERE timestamp >= NOW() - INTERVAL 7 DAYS
AND timestamp <= NOW();
And then breaking that up into 8 hour blocks, and averaging the contents of each block. (each block should have 12 rows, and there should be 3 blocks per day).
try
SELECT avg(`value`)
FROM `table`
WHERE timestamp >= NOW() - INTERVAL 7 DAY AND timestamp <= NOW()
group by concat(date(`timestamp`), case when hour(`timestamp`) between 0 and 7 then 1
when hour(`timestamp`) between 8 and 15 then 2
else 3 end)
If you are not tied by only doing it in your request, you could try the following method of splitting the intervals before doing the request :
boundary1 = NOW()
boundary2 = NOW()
FOR i = 0 to 21 //7 days, 3 intervals of 8 hours per days
boundary1 = boundary2
boundary2 = boundary1 - seconds(8 hours)
req = "SELECT timestamp, value FROM table WHERE timestamp >= "+boundary2+" AND timestamp <= "+boundary1
ENDFOR
I'm afraid this is probably a very embarrassingly easy question - but my mind is just completely stuck at this hour.
I have a table that stores the number of activities carried out by different people, and the time it took place in.
I want to create a report that accepts the person's name as a parameter, and show the number of activities per hour for that person during each of the previous 24 hours starting from current timestamp (now()).
Right now,
SELECT hour(TimeStamp), activities FROM tbl1
WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 24 HOUR) AND Name = ?
GROUP BY hour(timestamp)
only returns to me those hours when any activity was present. However, I want a complete 24 hour breakdown with zero for when there was no activity.
i.e. I'm getting
Hour | No. of Activities
1 | 34
4 | 22
9 | 86
but I want
Hour | No. of Activities
1 | 34
2 | 0
3 | 0
4 | 22
5 | 0
... etc.
How do I do this?
(The order of hours in the example is irrelevant)
You can create a hourly table, and do a LEFT JOIN
create table hourly
(
/* hour is not a reserved keyword */
hour smallint(2) not null default 0
);
insert into hourly values (0),(1).... until 24
SELECT
hourly.hour,
COALESCE(COUNT(activities),0) AS "No of Activities"
FROM hourly
LEFT JOIN tbl1 ON hourly.hour=hour(tbl1.TimeStamp)
WHERE
tbl1.timestamp>=DATE_SUB(NOW(), INTERVAL 24 HOUR) AND
tbl1.Name=?
GROUP BY hourly.hour
ORDER BY hourly.hour;