mysql get sum of hours / minutes / seconds - mysql

I have a table with: userid and timestamp each time a user opens a page a new field is inserted.
I am trying to get the total amount of hours / minutes / days / weeks that appear in a 1 month interval for multiple users.
I have tried a bunch of different queries but each have ended up terribly inefficient.
Ideally I'd like to end up with something like:
userid | minutes | hours | days | weeks
1 10080 168 7 1
2 1440 24 1 0
Hopefully someone can shed some light on how to do this.
Below is a query that I tried:
SELECT
w.time AS `week`,
d.time AS `day`,
h.time AS `hour`,
m.time AS `minutes`
FROM (
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT WEEK( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) w,
(
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT DAY( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "52"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) d,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT HOUR( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY DAY( `timestamp` )
) t
) h,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT MINUTE( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY HOUR( `timestamp` )
) t
) m
It seems awfully excessive for this task, maybe someone has something better?

It's not clear to me what you want to "total".
If you want to determine whether a user had a "hit" (or whatever transaction it is you are storing in the table) at any given minute within the month), and then you want to count the number of "minute periods" within a month that a user had a hit:
SELECT t.userid
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H:%i')) AS minutes
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H' )) AS hours
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d' )) AS days
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%X-%V' )) AS weeks
FROM mytable t
WHERE t.timestamp >= '2012-06-01'
AND t.timestamp < '2012=07-01'
GROUP BY t.userid
What this is doing is taking each timestamp, and putting it into a "bucket", by chopping off the seconds, chopping off the minutes, chopping off the time, etc.
Basically, we're taking a timestamp (e.g. '2012-07-25 23:15:30') and assigning it to
minute '2012-07-25 23:15'
hour '2012-07-25 23'
day '2012-07-25'
A timestamp of '2012-07-25 23:25:00' would get assigned to
minute '2012-07-25 23:25'
hour '2012-07-25 23'
day '2012-07-25'
Then we go through and count the number of distinct buckets we assigned a timestamp to. If that's all the hits for this user in the month, the query would return a 2 for minutes, and a 1 for all other period counts.
For a user with a single hit within the month, all the counts for that user will be a 1.
For a user that has all their "hits" within exactly the same minute, the query will again return a 1 for all the counts.
(For a user with no "hits" within a month, no row will be returned. (You'd need to join another row source to get a list of users, if you wanted to return zero counts.)
For a user with a "hit" every second within a single day, this query will return counts like that shown for userid 2 in your example.
This result set gives you a kind of an indication of a user's activity for a month... how many "minute periods" within a month the user was active.
The largest value that could be returned for "days" would be the number of days in the month. The largest possible value to be returned for "hours" would be 24 times the number of days in the month times. The largest possible value returned for "minutes" would be 1440 times the number of days in the month.
But again, it's not entirely clear to me what result set you want to return. But this seems like a much more reasonable result set than the one from the previously "selected" answer.

SELECT userid, SUM(MINUTE(timestamp)) AS minutes, SUM(MINUTE(timestamp))/60 AS hours, SUM(MINUTE(timestamp))/(60*24) AS days, SUM(MINUTE(timestamp))/(60*24*7) AS weeks
FROM Table
GROUP BY userid
If neccesary, use ROUND(SUM(MINUTE(timestamp)), 0) if you want integer numbers.

Related

Mysql - Get data of different time interval in same query

My below query is giving me result of top videos played in past 2 hours, but my requirement is to also get top videos of past 4 hours to past 2 hours, for example if by this query I am getting data from 01:00 PM to 03:00 PM, I also want data from 09:00 AM to 01:00 PM. Can I do this in one query and in efficient way.
Query:
select SQL_CACHE channel,SUBSTRING_INDEX(GROUP_CONCAT(video_id ORDER BY plays DESC),',', 40) AS video_ids,now() as datetime from
(SELECT channel,video_id,count(video_id) as plays FROM `tbl`
WHERE `datetime_col` > DATE_SUB( now(), INTERVAL 2 HOUR )
and channel != 0
and cat_id != 8
group by channel,video_id
order by channel,plays DESC)x
group by channel;
Thanks in advance.
You can use the same query with UNION to group the results. Also, you can use BETWEEN to define the intervals, e.g.
select SQL_CACHE channel,SUBSTRING_INDEX(GROUP_CONCAT(video_id ORDER BY plays DESC),',', 40) AS video_ids,now() as datetime from
(SELECT channel,video_id,count(video_id) as plays FROM `tbl`
WHERE `datetime_col` BETWEEN DATE_SUB( now(), INTERVAL 2 HOUR ) AND NOW()
and channel != 0
and cat_id != 8
group by channel,video_id
order by channel,plays DESC)x
group by channel
UNION
select SQL_CACHE channel,SUBSTRING_INDEX(GROUP_CONCAT(video_id ORDER BY plays DESC),',', 40) AS video_ids,DATE_SUB( now(), INTERVAL 2 HOUR ) as datetime from
(SELECT channel,video_id,count(video_id) as plays FROM `tbl`
WHERE `datetime_col` BETWEEN DATE_SUB( now(), INTERVAL 4 HOUR ) AND DATE_SUB( now(), INTERVAL 2 HOUR )
and channel != 0
and cat_id != 8
group by channel,video_id
order by channel,plays DESC)x
group by channel;

Why am i getting this error message ( #1111 - Invalid use of group function )?

I am trying to retrieve the TIMEDIFF from the last_call field of every row, where TIMEDIFF between current row and next row is greather than 10 min!
Can someone please help? Meybe there is a better way of doing this?
My goal is to get the total of all timediff between severall database entrys but only if they are greather than 10 min.
SELECT DATE_FORMAT( last_call, '%d' ) AS 'day',
(
SELECT TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call)))
FROM calls AS cl1
WHERE TIME_TO_SEC(TIMEDIFF(MAX(cl1.last_call), MIN(cl1.last_call))) > 600
AND cl1.calling_agent=9
AND EXTRACT(DAY FROM cl1.last_call ) = EXTRACT(DAY FROM calls.last_call )
) AS 'brake'
FROM calls
WHERE calling_agent =9
AND last_call > DATE_SUB( now( ) , INTERVAL 12 MONTH )
GROUP BY EXTRACT( DAY FROM last_call )

How to display tree results count by each month?

I am trying to count achieve 3 results in one query:
Count all results where ‘app_creationdate’ = ('month') from current row
Count all results where ‘app_start’ = ('month') from current row
Count all results where ‘app_creationsdate’ < ‘app_start’ and ‘app_start’ = ('month') from current row
My Table:
app_id | app_creationdate(timestamp) | app_start(datetime)
00001 | 2014-11-17 19:39:04 | 2014-11-18 09:30:00
SELECT
DATE_FORMAT( app_creationsdate, '%m' ) AS 'month',
COUNT( app_id ) AS 'new',
(SELECT COUNT( app_id )
FROM appointments WHERE MONTH(app_start) = MONTH(NOW())) AS 'act',
(SELECT COUNT( app_id )
FROM appointments WHERE MONTH(app_creationsdate) < MONTH(app_start)) AS 'prev'
FROM appointments
WHERE app_owner = 2 AND app_creationsdate > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY DATE_FORMAT( app_creationsdate, '%Y%m' )
This may be closer to what you want. I'm still a bit confused about the prev scenario, so I did my best. I use EXTRACT(YEAR_MONTH FROM ...) to get the year and month, without the day, of each date so that we can do monthly comparisons. That's probably what you were trying to do with the DATE_FORMAT business.
SELECT DATE_FORMAT( app_creationsdate, '%m' ) AS 'month',
COUNT( app_id ) AS 'new',
-- get all other appointments that start in this month
(SELECT COUNT( act.app_id )
FROM appointments AS act
WHERE EXTRACT(YEAR_MONTH FROM act.app_start) = EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)) AS 'act',
-- get all appointments that were created before they started (???) and that started before this month
(SELECT COUNT( prev.app_id )
FROM appointments AS prev
WHERE EXTRACT(YEAR_MONTH FROM prev.app_creationsdate) < EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)
AND EXTRACT(YEAR_MONTH FROM prev.app_start) = EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)) AS 'prev'
FROM appointments
WHERE app_owner = 2
AND app_creationsdate > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY EXTRACT(YEAR_MONTH FROM app_creationsdate)
I am not entirely sure what you are trying to accomplish but I do notice one thing:
DATE_FORMAT(a2.app_start, '%m' ) = DATE_FORMAT('month', '%m' )
This: DATE_FORMAT('month', '%m' )...evaluates to NULL so equating that with anything is never going to work (I don't think anyway, but I'm new to MySQL... :) ).

MySql sum records daily from 2:00 am instead of midnight.

For a business closing at 2:00 am, daily accounting ends then. How do I write or simplify this query to sum daily traffic where the top of the clock is actually at 2:00.
SELECT date( CAST( Time - INTERVAL 2 HOUR AS DATETIME ) ) AS date,
CAST( (sum( `in_count` ) + sum( `out_count` ) ) /2 AS UNSIGNED) AS count
FROM establishment
LEFT JOIN `device` ON establishment.establishment_ID = device.establishment_ID
LEFT JOIN `device_state` ON device.device_id = device_state.device_ID
WHERE establishment.establishment_ID =1
AND date(CAST( Time - INTERVAL 2 HOUR AS DATETIME ))
BETWEEN '2013-02-01' AND '2013-03-01'
GROUP BY dayofmonth( CAST( Time - INTERVAL 2 HOUR AS DATETIME ))
ORDER BY Time

Mysql nested query optimization

I have a table that logs various transactions for a CMS. It logs the username, action, and time. I have made the following query to tell me how many transactions each user made in the past two days, but it is so slow its faster for me to send a bunch of separate querys at this point. Am I missing a fundamental rule for writing nested queries?
SELECT DISTINCT
`username`
, ( SELECT COUNT(*)
FROM `ActivityLog`
WHERE `username`=`top`.`username`
AND `time` > CURRENT_TIMESTAMP - INTERVAL 2 DAY
) as `count`
FROM `ActivityLog` as `top`
WHERE 1;
You could use:
SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
An index on (username, time) would be helpful regarding speed.
If you want users with 0 transcations (the last 2 days), use this:
SELECT DISTINCT
act.username
, COALESCE(grp.cnt, 0) AS cnt
FROM ActivityLog act
LEFT JOIN
( SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
) AS grp
ON grp.username = act.username
or, if you have a users table:
SELECT
u.username
, COALESCE(grp.cnt, 0) AS cnt
FROM users u
LEFT JOIN
( SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
) AS grp
ON grp.username = u.username
Another way, similar to yours, would be:
SELECT username
, SUM(IF(time > CURRENT_TIMESTAMP - INTERVAL 2 DAY, 1, 0))
AS count
FROM ActivityLog
GROUP BY username
or even this (because true=1 and false=0 for MySQL):
SELECT username
, SUM(time > CURRENT_TIMESTAMP - INTERVAL 2 DAY)
AS count
FROM ActivityLog
GROUP BY username
No need for nesting...
SELECT `username`, COUNT(`username`) as `count` FROM `ActivityLog` WHERE `time` > CURRENT_TIMESTAMP - INTERVAL 2 DAY GROUP BY `username`
Also don't forget to add an INDEX on time if you want to make it even faster