MySQL Query for obtaining count per hour - mysql

I need to obtain a count of how many actions occur on an hourly basis.
My database keeps a log by timestamp of the actions.
I understand that I could do a
SELECT table.time COUNT(table.time) from table t group by t.time
However, there are periods of time where no actions take place. For example if I have 10 actions during 8:00AM, no actions during 9:00AM and 4 actions during 10:00AM,
That query would return:
8:00 10
10:00 4
Skipping 9:00AM because it has no entries.
How can I make a query that will take into account 0-count entries.
I also need to make the same query for entries by days of the week, but I assume that by answering the first question I can easily handle the other.
Thanks in advance!

you can solve this by creating a table that will contain 24 values for hours (00:00, 01:00 etc) and perform a left (or right) join with it and your table allowing nulls so you will have all 24 rows even if your table contains 0 rows at all, then group by should work fine.
Dont forget to truncate everything but hour from your table when you perform join so result of func you call & perform join on can be equal to value of this help table.
you can use following query to do the job after populating testtime table with 24 test_time values
select test_time,sum(sign(coalesce(idFromYourTable,0))) as count from testtime
left join yourTable on test_time=hour(yourTableTime)
group by test_time
This will provide 0 as count if there are no values matching row from test table, while having count(*) will provide 24 rows with 1s instead of 0s even if your table is empty, also if there is just 1 row in your table it is impossible to distinguish the difference between 0 rows cause results will look the same for following 2 different rows
23 NULL
23 1
cause will both provide same result row count equal to 1 , while sum technique treats this rows differently

A simple way to do the same without creating any table would be as follows
SELECT
HOUR(time) 'hr', COUNT(DISTINCT id)
FROM schema.table
WHERE time BETWEEN '2016-01-23 00:00:00' AND '2016-01-24 00:00:00'
GROUP BY hr;
Hour function in mysql gives the hour from a datetime or timestamp data type. This query is grouping them based on particular hour withing the date range. Distinct is not mandatory but if you are looking for unique order or id in the time range per hour. This is the query.

You can use Valentin's solution but without the need to create a table of time slots. The idea is to generate the time slots on the fly and then JOIN them to your table as he suggests.
WITH RECURSIVE timeSlots (t) AS (
SELECT 0
UNION ALL
SELECT t + 3600 FROM timeSlots WHERE t < (23 * 3600)
)
SELECT t, TIME_FORMAT(SEC_TO_TIME(t), '%H:%i:%s') FROM timeSlots;
Gives:
+-------+----------+
| t | Time |
+-------+----------+
| 0 | 00:00:00 |
| 3600 | 01:00:00 |
| 7200 | 02:00:00 |
| 10800 | 03:00:00 |
| 14400 | 04:00:00 |
| 18000 | 05:00:00 |
| 21600 | 06:00:00 |
| 25200 | 07:00:00 |
| 28800 | 08:00:00 |
| 32400 | 09:00:00 |
| 36000 | 10:00:00 |
| 39600 | 11:00:00 |
| 43200 | 12:00:00 |
| 46800 | 13:00:00 |
| 50400 | 14:00:00 |
| 54000 | 15:00:00 |
| 57600 | 16:00:00 |
| 61200 | 17:00:00 |
| 64800 | 18:00:00 |
| 68400 | 19:00:00 |
| 72000 | 20:00:00 |
| 75600 | 21:00:00 |
| 79200 | 22:00:00 |
| 82800 | 23:00:00 |
+-------+----------+
If you want to change your time slot buckets you can just fiddle with the generator arithmetic rather than having to create another table.
An alternative is to use LIMIT:
WITH RECURSIVE timeSlots (t) AS (
SELECT 0
UNION ALL
SELECT t + 3600 FROM timeSlots LIMIT 24
)
SELECT t, TIME_FORMAT(SEC_TO_TIME(t), '%H:%i:%s') AS Time FROM timeSlots;

Related

How to write a SQL statement to get the number of concurrent screen views from table

I have the following table:
user_id | timestamp. | post_number
123 | 2022-04-01 17:32:52 UTC | 1
234 | 2022-04-01 17:35:52 UTC | 1
546 | 2022-04-01 17:32:52 UTC | 1
765 | 2022-04-01 18:32:52 UTC | 1
143 | 2022-04-01 17:32:54 UTC | 1
123 | 2022-04-01 18:32:52 UTC | 2
234 | 2022-04-01 18:32:53 UTC | 2
546 | 2022-04-01 18:40:02 UTC | 2
I want to count the number of users with concurrent screen views (define concurrent as within 2 second of each other) for each post.
My desire output will look like this:
post_number | concurrent_screeenviews
1 | 3
2 | 4
For a particular timestamp, it will be as simple as a TIMESTAMPDIFF but how do I iterate over the entire timestamps in a given day?
I am using MySQL in BigQuery.
If I understand your question correctly, you could try something like this. In the inner query, I've used the lag function to order the timestamp, then the current timestamp with the previous timestamp to see if it's within 2 seconds. However, the 1st timestamp for each post number won't be counted in the inner query, so I've added it in the outer query.
SELECT t.postnumber, 1+SUM(t.cnt) as concurrent_screeenviews FROM (
SELECT postnumber,
time_stamp,
if (time_stamp - LAG(time_stamp) over (partition by postnumber order by time_stamp) <= 2, 1, 0) as cnt
FROM table1
) AS t
group by t.postnumber
db fiddle link

Expand query result in select where statement

I need to get all the values between two dates on the same table, but also, include the value immediately before the earliest one:
To be more clear, I have the following table (Table 1. with aprox. 46 million rows):
Table 1. (Table I have)
updatetime | value
. .
. .
2018-01-01 08:32:02 | 2
2018-01-01 09:23:12 | 5
2018-01-01 10:45:00 | 8 * value to include on the result.
2018-01-01 11:10:44 | 10 * <-- earliest date.
2018-01-01 13:11:54 | 12 *
2018-01-01 16:14:57 | 16 *
2018-01-01 20:00:55 | 22 *
2018-01-01 22:34:43 | 23 *
2018-01-01 23:55:23 | 23 * <-- latest date.
2018-01-02 01:03:57 | 25
2018-01-02 03:39:07 | 28
. .
. .
I have accumulative values, so, the next value will always be equal or greater than the one before. I need to get all values between 2018-01-01 11:10:44 and 2018-01-02 01:03:57, but, I also need the value before the earliest date, that means that I need this result: (Table 2.)
Table 2. (Result I need)
2018-01-01 10:45:00 | 8
2018-01-01 11:10:44 | 10
2018-01-01 13:11:54 | 12
2018-01-01 16:14:57 | 16
2018-01-01 20:00:55 | 22
2018-01-01 22:34:43 | 23
2018-01-01 23:55:23 | 23
As you could see in Table 1, date spaces are not the same, so, previous date of the earliest date is unknown to me, and value incrementation is also random.
I already tried theese two queries, but I have doubts about performance:
The first one is just two queries made one, very bad performance because of the change of order of the table.
SELECT * FROM his
WHERE updatetime>=(
SELECT updatetime
FROM definition
WHERE updatetime<"2018-01-01 11:10:44"
ORDER BY updatetime DESC
LIMIT 1
) and updatetime<="2018-01-02 01:03:57";
The second should be slower than the first one, but if I define the column as incremental to make MySQL walk the table from the last value of the condition and not to walk all over it?
SELECT * FROM his
WHERE updatetime>=(
SELECT MAX(updatetime)
FROM definition
WHERE updatetime<"2018-01-01 11:10:44"
LIMIT 1
) AND updatetime<="2018-01-02 01:03:57";
First of all, for these queries to perform efficiently, you would need an index on column updatetime :
CREATE INDEX idx_updatetime ON mytable(updatetime);
One way to do it would to use a correlated subquery in the WHERE clause that selects the previous record :
SELECT t.*
FROM mytable t
WHERE
t.updatetime < '2018-01-02 01:03:57'
AND NOT EXISTS (
SELECT 1
FROM mytable t1
WHERE t1.updatetime < '2018-01-01 11:10:44' AND t1.updatetime > t.updatetime
)
Demo on DB Fiddle :
| updatetime | value |
| ------------------- | ----- |
| 2018-01-01 11:10:44 | 10 |
| 2018-01-01 13:11:54 | 12 |
| 2018-01-01 16:14:57 | 16 |
| 2018-01-01 20:00:55 | 22 |
| 2018-01-01 22:34:43 | 23 |
| 2018-01-01 23:55:23 | 23 |
Another option is to compute the updatetime of the previous record in a subquery, and then use it to filter the table. This might perform better than the first query.
SELECT t.*
FROM mytable t
INNER JOIN (
SELECT MAX(updatetime) updatetime
FROM mytable
WHERE updatetime < '2018-01-01 11:10:44'
) x ON t.updatetime >= x.updatetime AND t.updatetime < '2018-01-02 01:03:57';
Demo on DB Fiddle

Mysql query difference between time fields has 24 hours

how i can check time difference between two time fields,having 24 hours
consider my table "tb1",that has following fields id,startTime,endTime
we need find out sum of time difference between(startTime,endTime) has 24 hours with add number min as total records.that means if total difference 14.44 minutes.total count records is 4,we need add four minutes to total hours
Below query i have tired:
Sample data
Select id,StartTime, EndTime from tablename;
+----+-----------+----------+
| id | StartTime | EndTime |
+----+-----------+----------+
| 40 | 00:00:00 | 02:59:00 |
| 41 | 04:00:00 | 05:59:00 |
| 42 | 06:00:00 | 13:29:00 |
| 43 | 15:00:00 | 18:29:00 |
+----+-----------+----------+
Select Sum(TIMESTAMPDIFF(EndTime, StartTime)) + 4 mintues from tablename;
Desired output:
12(in hours)
Thanks in advance
Assuming that you always add the number of records as minutes
SELECT SEC_TO_TIME((SUM(TIMESTAMPDIFF(MINUTE, StartTime, EndTime)) + COUNT(*)) * 60)
FROM tablename;
With your data this will return H:M:S
16:00:00
http://sqlfiddle.com/#!9/953c0c/21
SELECT round(sum((time_to_sec(timediff(EndTime,StartTime))/3600)+(4/60)))
FROM TABLE
limit 1;

How to select records form a table with current date and custom time range?

I am having a table with seperate date and time column. I need to select all data from my table checking two condition
1.records with current date(todays date).
2.records with custom time range.
This is my table structure
+------------+------------+---------------------+-------------------+--------------------+
| id | item | description | bill_date | bill_time |
+------------+------------+---------------------+-------------------+--------------------+
| 1 | x | test | 2016-04-15 | 12:05:00 |
+------------+------------+---------------------+-------------------+--------------------+
| 2 | y | test1 | 2016-04-15 | 01:10:44 |
+------------+------------+---------------------+-------------------+--------------------+
| 3 | z | test2 | 2016-04-16 | 05:10:10 |
+------------+------------+---------------------+-------------------+--------------------+
I could select time range using this mysql query
SELECT * FROM `bill_item` WHERE `bill_time` BETWEEN '12:00:00' AND '06:00:00'
this returns 2,3 record now I need to check if the record is todays record. How to do this?
It is possible to have multiple conditions in the WHERE clause. You can use CURRENT_DATE() or NOW() to get only todays entries.
SELECT *
FROM `bill_item`
WHERE (bill_time BETWEEN '12:00:00' AND '06:00:00')
AND bill_date = CURRENT_DATE()
See the official documentation for more Date and Time Functions

MySQL - query help select results with latest timestamp grouped by date

I have a table containing the following fields:
date, time, node, result
describing some numeric result for different nodes at different dates and times throughout each day. Typical listing will look something like this:
date | time | node | result
----------------------------------
2011-03-01 | 10:02 | A | 10
2011-03-01 | 11:02 | A | 20
2011-03-02 | 03:13 | A | 23
2011-03-02 | 12:15 | A | 18
2011-03-02 | 13:15 | A | 8
2011-03-01 | 13:12 | B | 2
2011-03-01 | 14:26 | B | 1
2011-03-02 | 08:00 | B | 6
2011-03-02 | 07:22 | B | 3
2011-03-02 | 21:19 | B | 4
I want to form a query that'll get the last result from each day for each node, such that I'd get something like this:
date | time | node | latest
-----------------------------------
2011-03-01 | 11:02 | A | 20
2011-03-01 | 14:26 | B | 1
2011-03-02 | 13:15 | A | 8
2011-03-02 | 21:19 | B | 4
I thought about doing a group by date, node, but then extracting the last value was a mess (I used group_concat( result order by time ) and used SUBSTRING() to get the last value. Baah, I know). Is there a simple way to do this in mysql?
I'm pretty sure I saw a similar request solving it very nice without using an INNER JOIN but I can't find it right now (and it might have been SQL Server) but following should work nevertheless.
SELECT n.*
FROM Nodes n
INNER JOIN (
SELECT MAX(time) AS Time
, Date
, Node
FROM Nodes
GROUP BY
Date
, Node
) nm ON nm.time = n.time
AND nm.Date = n.Date
AND nm.Node = n.Node
I would think that you would have to use something like the Max() function. Sorry I don't have mysql, so I can't test but I would think something like this
select t.date, t.node, t.latest, Max(time) from Table t Group By t.node, t.date
I think the aggregate function will return only the one row per grouping.