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;
Related
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.
I need to store durations such as the following in mysql:
- 30 seconds
- 20 minutes, 12 seconds
- 1 month
What would be the best way to store this, as the definition of a month can't be reduced, for example, to a number of seconds. My first thought was to store each increment separate, for example:
- num_seconds
- num_minutes
- num_hours
- num_days
- num_months
This could store the above, but I was hoping there was a more direct and less verbose way of doing this.
My first option would be to store duration as a number of seconds with datatype INT. This will make computation and comparison operations fast and clean. Also you can easily compute the duration between two datetime values, by substracting their Unix timestamp. When you need to display the values, you can use mysql sec_to_time function :
However if you are looking to manipulate big durations (months, years), this will not work. In that case I would fallback on a VARCHAR column with iso8601 duration format, like P3Y6M4DT12H30M5S for 3 years, 6 months, 4 days, 12 hours, 30 minutes and 5 seconds. It is a well known format that is supported by many applications (but will be more tedious to manipulate).
Store your intervals for years to months as an integer counting the number of months (12 months = 1 year) and your intervals for days to seconds as an integer of number of seconds.
You can then use the DATE_ADD function to figure out your dates. Here's a SQL Fiddle example showing storing intervals as months and seconds, and adding them to a fixed date:
MySQL 5.6 Schema Setup:
create table mytab (dt date);
insert into mytab values (date '2018-01-01');
create table intervals (months int, seconds int);
insert into intervals values (13, 3661), (-13, -3661);
Query 1:
select dt
, months
, seconds
, date_add(date_add(dt, interval months month)
, interval seconds second) result
from mytab cross join intervals
Results:
| dt | months | seconds | result |
|------------|--------|---------|----------------------|
| 2018-01-01 | 13 | 3661 | 2019-02-01T01:01:01Z |
| 2018-01-01 | -13 | -3661 | 2016-11-30T22:58:59Z |
I'm setting up a calendar on which users can indicate when they are available. The calendar is split up in 3 time slots per day, for 7 days a week (monday-morning, monday-afternoon, monday-evening).
I'm a bit stuck on what the best way would be to store this in my database. I've thought about doing:
start_date
end_date
user_id
or
timeslot
user_id
or
user_id&
mon1
mon2
mon3
...
sun3
creating 21 columns doesn't seem optimal, but it does make the availability query very easy.
I would like to keep some flexibility in defining the hours for the slots. The second one appears to give me this, as I can just define the hours per day afterwards.
In the end I have to be able to look up who is available on 2019-02-01 13:00:00 - 2019-02-01 17:15:00. These dates will not correspond with the timeslots.
You can use 3 fields to store this information,
slot_date - to store date of slot like 2018-12-17, 2018-12-18, etc
slot_time - to store time slot like 13:00:00, 15:00:00, etc
user_id - to store user identifier
Let's say your sample data for 2 users with these fields will look somewhat like this,
slot_date slot_time user_id
---------------------------------
2018-12-17 14:00:00 1
2018-12-17 17:00:00 2
You can easily get the availability of the users for a given time slot. For instance, you want to fetch today's availability for afternoon slot ( considering 1 pm to 4 pm is evening slot ), which can be retrieved by following query,
SELECT slot_date, slot_time, user_id
FROM tbl_slot
WHERE slot_date = '2018-12-17'
AND slot_time BETWEEN '13:00:00' AND '15:00:00'
Similarly, you can change the slot_time clause in the query to work for morning and evening slots.
Update
Based on OP's requirement, if a user selects a day and a slot it will be applicable for every month/year. Based on it, you an eliminate the slot_date column and use day_of_week that will store integer values from 1 to 7 i.e. (Sun to Sat)
day_of_week slot_time user_id
-----------------------------------
2 14:00:00 1
2 17:00:00 2
Then, the query to get all afternoon availability will be,
SELECT day_of_week, slot_time, user_id
FROM tbl_slot
WHERE day_of_week = '2'
AND slot_time BETWEEN '13:00:00' AND '15:00:00'
What I am trying to achieve is grab data from the database, depending on the time.
For example, I may have multiple prices for an item, and I would like the new price to be effective based on the time and date. So I can schedule price changes in advance.
id link_id datetime price
-------------------------------------------
2 11 2016-11-03 00:00:00 1020
3 11 2016-11-03 01:00:00 1050
4 11 2016-11-03 03:00:00 1090
Let's say the time is 2016-11-03 00:59:00, when a user queries the db they will se the price-1020. But when they query the db a minute later at 2016-11-03 01:00:00 they should get price-1050.
Have tried this WHERE datetime < UTC_TIMESTAMP(), however this does not solve my problem. Also it only needs to select one entry, this selects multiple.
Is there a way MySQLi can do this?
If you are only looking for one item, I would expect something like this:
select p.*
from prices p
where p.item_id = $item_id and -- however you are representing items
p.datetime <= now() -- or UTC Timestamp if that is how the date/time is represented
order by p.datetime desc
limit 1;
I could speculate that "link_id" refers to "items".
For example, given 1339372800, which is Mon, 11 Jun 2012 00:00:00 GMT, I would like to get the next X hours including 1339372800. So for the next 3 hours, the result would be
+------------+
| hours |
+------------+
| 1339372800 |
| 1339376400 |
| 1339380000 |
+------------+
I think I need to create a loop but I don't know how to proceed from that. Thanks.
You could use a numbers table as Creating a "Numbers Table" in mysql that contains all hours for a considerate amount of time, and query that:
SELECT hour
FROM hours
WHERE hour >= 1339372800
ORDER BY hour ASC
LIMIT 3
That makes the query really easy, and the table should not be too big, either. (Less than 90k rows for 10 years.)
Try:
SELECT *
FROM table
WHERE
hours between 1339372800 and DATE_SUB(1339372800, INTERVAL 3 HOUR)