Best way to determine if a user went offline in MySQL - mysql

So my script currently forces the user to send a "ping" every 10 minutes. This inserts a record into MySQL with the user ID and the current timestamp.
What I would like to achieve is seeing if any of the users went offline recently.
In theory that would be selecting a recently online (20ish minutes ago) user, then checking if there has not been a ping in the past 11 minutes except I don't seem to be able to figure out how.
This is what I have so far:
SELECT * FROM status WHERE time > (CURTIME() - 1200) AND time < (CURTIME() - 660)
I have to add, I do this in combination with PHP but that shouldn't really matter.
Any help is appreciated.

I would try something like that :
SELECT TIMEDIFF(CURTIME(), MAX(s.time)) AS duration, s.user
FROM status s
GROUP BY s.user
HAVING duration > 660 AND duration < 1200;
If the username is not stored in the status table. You should perform a JOIN between Status and User.
You can use a BETWEEN statement if you want to check duration for a specific range too.
EDIT : Thanks to Madbreaks about the "recently" constraint. You can add a AND duration < xxxx to do not retrieve old durations and keep only "recent" status in your result set.

There are a lot of ways to do this. Here's one, assuming you have a primary key called id:
SELECT *
FROM status
LEFT JOIN (
SELECT id
FROM status
WHERE time > (CURTIME() - 660) // was on within last 5 minutes
) sub ON
sub.id = status.id
WHERE
time > (CURTIME() - 1200) // was on within last 20 minutes
AND sub.id IS NULL; // was on within last 20, but not last 5

Use between for that:
SELECT *
FROM `status`
WHERE (`time` BETWEEN (CURTIME() - 660) AND (CURTIME() - 1200))

Related

MySql Sum of Count If

I have a table with every login by all users.
I want to run a query that will pull the number of times each user logs in but limit it to 4 if the user logged in more than 4 times on a day.
And then do a sum to get the total number of logins.
Further to this I want to pull back the time frame for the total number of logins. So I specify the total number of logins as 100 then the query must pull back the earliest date, going back from today and counting the number of logins (limited at 4 if above 4) per user.
My query so far to get the list of totals limited to 4 per user:
SELECT (case when (count(l.user_id) > 4) then 4 else count(l.user_id) end) as cappedcount
FROM `logins` l
where l.store_id = 908
and l.login_dt > '2018-04-17 00:00:00' and l.login_dt < '2018-04-18 23:59:59'
group by l.user_id order by cappedcount desc
I'm specifying the date range at the moment but don't want to do that in the final query.
If I understand correctly, you only want to look at the last four logins per user and day and ignore their earlier logins. From this set you want the last 100 logins.
So the first task is to get the four last logins per user and day, which would usually be solved with window functions, but MySQL doesn't feature them. So count in a subquery instead (which may take long):
select *
from logins
where
(
select count(*)
from logins later
where later.user_id = logins.user_id
and date(later.login_dt) = date(logins.login_dt)
and later.login_dt > logins.login_dt
) < 4
order by login_dt desc
limit 100;
I suggest to provide the following index for this query:
create index idx_logins on logins (user_id, login_dt);
What is the version of MySQL you user? Because as far as I know with clause is only supported in recent versions of MySQL.
I believe the answer to your first request is something like :
select sum(cntx) from (
select user_id, date(login_time), least(count(*), 4) cntx
from logins
where login_time between '2018-04-10 00:00:00' and '2018-04-17 00:00:00'
group by user_id, date(login_time)
) x
as you can view it in sqlfiddle.com.
For your second question, I have following answer, I believe it's not the best solution, but it works on MySQL 5.6. In next MySQL version (MySQL 8) you can use with clause which provides better solution for this question. I use views in the solution to skip duplicate queries:
create view xlogins as
select user_id, date(login_time) xdt, least(count(*), 4) xcnt
from logins
group by user_id, date(login_time);
create view xxlogins as
select distinct xdt, (select sum(x2.xcnt)
from xlogins x2
where x2.xdt >= x1.xdt) sumx
from xlogins x1;
select min(x1.xdt)
from xxlogins x1
join xxlogins x2 on x1.xdt < x2.xd
where x1.sumx >= 100
and x2.sumx <= 100
Find the solution in this sqlfiddle.com, I've just changed the 100 to 10.

MySQL checking if user last logins timestamps are always less than session timestamps

Hopefully, the image/diagram helps explain what I'm trying to do...
Been going round-and-round, nothing seems to work, this is the my most recent attempt:
SELECT * FROM sessions
(
SELECT sessions.timestamp AS stimestamp
users.last_login AS ulastlogin
FROM sessions, users
WHERE sessions.user_id = users.user_id
ORDER BY sessions.timestamp DESC LIMIT 1
)
WHERE ulastlogin < stimestamp;
I'd like to have a SQL query to check to make sure that users' last_login timestamps are always larger (more recent) than the actual user sessions...
Someone at work helped me and I ended-up just using this... Thanks D.B.!!!
I did have to de-dupe in Excel, but other than that, it seemed to do the trick:
SELECT * FROM users, sessions
WHERE sessions.timestamp > unix_timestamp() - 3600*24
AND users.user_id = sessions.user_id
AND users.last_login < sessions.timestamp;
It grabs what I need for the last 24 hours, so I can do sub-selections by date range.

Group by date from multiple columns?

first of all sorry for that title, but I have no idea how to describe it:
I'm saving sessions in my table and I would like to get the count of sessions per hour to know how many sessions were active over the day. The sessions are specified by two timestamps: start and end.
Hopefully you can help me.
Here we go:
http://sqlfiddle.com/#!2/bfb62/2/0
While I'm still not sure how you'd like to compare the start and end dates, looks like using COUNT, YEAR, MONTH, DAY, and HOUR, you could come up with your desired results.
Possibly something similar to this:
SELECT COUNT(ID), YEAR(Start), HOUR(Start), DAY(Start), MONTH(Start)
FROM Sessions
GROUP BY YEAR(Start), HOUR(Start), DAY(Start), MONTH(Start)
And the SQL Fiddle.
What you want to do is rather hard in MySQL. You can, however, get an approximation without too much difficulty. The following counts up users who start and stop within one day:
select date(start), hour,
sum(case when hours.hour between hour(start) and hours.hour then 1 else 0
end) as GoodEstimate
from sessions s cross join
(select 0 as hour union all
select 1 union all
. . .
select 23
) hours
group by date(start), hour
When a user spans multiple days, the query is harder. Here is one approach, that assumes that there exists a user who starts during every hour:
select thehour, count(*)
from (select distinct date(start), hour(start),
(cast(date(start) as datetime) + interval hour(start) hour as thehour
from sessions
) dh left outer join
sessions s
on s.start <= thehour + interval 1 hour and
s.end >= thehour
group by thehour
Note: these are untested so might have syntax errors.
OK, this is another problem where the index table comes to the rescue.
An index table is something that everyone should have in their toolkit, preferably in the master database. It is a table with a single id int primary key indexed column containing sequential numbers from 0 to n where n is a number big enough to do what you need, 100,000 is good, 1,000,000 is better. You only need to create this table once but once you do you will find it has all kinds of applications.
For your problem you need to consider each hour and, if I understand your problem you need to count every session that started before the end of the hour and hasn't ended before that hour starts.
Here is the SQL fiddle for the solution.
What it does is use a known sequential number from the indextable (only 0 to 100 for this fiddle - just over 4 days - you can see why you need a big n) to link with your data at the top and bottom of the hour.

Mysql maximum rows in a variable timeframe

I'm making a fitness logbook where indoor rowers can log there results.
To make it interesting and motivating I'm implementing an achievement system.
I like to have an achievement that if someone rows more than 90 times within 24 weeks they get that achievement.
Does anybody have some hints in how i can implement this in MYSQL.
The mysql-table for the logbook is pretty straightforward: id, userid, date (timestamp),etc (rest is omitted because it doesn't really matter)
The jist is that the first rowdate and the last one can't exceed the 24 weeks.
I assume from your application that you want the most recent 24 weeks.
In mysql, you do this as:
select lb.userid
from logbook lb
where datediff(now(), lb.date) >= 7*24
group by userid
having count(*) >= 90
If you need it for an arbitrary 24-week period, can you modify the question?
Just do a sql query to count the number of rows a user has between now and 24 weeks ago. This is a pretty straight forward query to run.
Look at using something with datediff in mysql to get the difference between now and 24 weeks ago.
After you have a script set up to do this, set up a cron job to run either every day or every week and do some automation on this.
I think you should create a table achievers which you populate with the achievers of each day.
You can set a recurrent(daily, right before midnight) event in which you run a query like this:
delete from achievers;
insert into achievers (
select userid
from logbook
where date < currenttimestamp and date > currenttimestamp - 24weeks
group by userid
having count(*) >= 90
)
For events in mysql: http://dev.mysql.com/doc/refman/5.1/en/events-overview.html
This query will give you the list of users total activity in 24 weeks
select * from table groupby userid where `date` BETWEEN DATE_SUB( CURDATE( ) ,INTERVAL 168 DAY ) AND CURDATE( ) having count(id) >= 90

How to calculate hours in mysql

My problem is in brief here...
Once a user signed in i stored his login date in the users table. If the user doesn't logged in for 72 hours i need to change his status to inactive.
How can i able to find whether 72 hours is completed or not after the user logged in using My Sql.
Thanks in advance...
I'd recommend using the TIMEDIFF() function, which you can find documented here:
dev.mysql.com timediff doc.
In your case, I'd format my where clause something like this:
WHERE
TIMEDIFF(CURTIME(), LastLoginDate) > '3 0:0:0.0'
or
WHERE
TIMEDIFF(CURTIME(), LastLoginDate) > '72:0:0.0'
I haven't done this specifically, but the base concept should work for you.
Create a CRON routine to run every hour with this query:
UPDATE users
SET status = 'Inactive'
WHERE (SELECT * FROM users WHERE last_login < now() - 259200)
To answer your question more specifically, it is the where clause, when ran, that tells you all the users that haven't logged in for 72 hours.
SELECT * FROM users WHERE last_login < now() - 259200
However, there is no way to set each user to inactive at exactly 72 hours. To get more accurate than the solution provided above, run the query more often.
*Note - insert your columns names where appropriate. Query not tested. 259200 = # of seconds in 72 hours - assumes you store your timestamps seconds (Epoch)
Use DATETIME type to store dates, subtract 72 hours from NOW() using DATE_SUB() and see if the result is larger than the value stored in the database.