Prior row depends on value of current row - mysql

The following query shows login information based on the userId. If a user closes their browser without logging off or the session expires, the logoff_date will remain null as in the example below.
userId logon_date logoff_date
1 2012-01-01 10:00:00 2012-01-01 12:00:00
1 2012-01-01 09:00:00 NULL
Because there is a newer logon_date of 2012-01-01 10:00:00, I know that the user must have killed the session for the login_date of 2012-01-01 09:00:00.
Here is my query:
SELECT userId, logon_date, logoff_date
FROM user_logon
WHERE user_id = 2
What I would like is to count only active sessions. In order to do this, I need to skip the rows where the logoff_date is missing if there is a newer row with the same userId.

How about this:
SELECT l.*
FROM user_logon l
INNER JOIN (SELECT MAX(logon_date) mdate,
user_id
FROM user_logon
GROUP BY user_id) x ON x.user_id = l.user_id
AND l.logon_date = x.mdate
WHERE l.logoff_date IS NULL
?
PS: This query implies that for each date there is only one record for particular user

Related

SQL query to get multiple rows with different timestamps

I am attempting get some data with their latest timestamps. sets of data have different timestamps which i need to get using their timestamps. for example:
id
testcase_id
user
timestamp
1
2
abbc
2013-01-13 15:00:00
2
2
pbbb
2013-01-13 15:05:00
3
4
dddd
2013-01-13 15:05:00
4
4
abbc
2010-01-10 16:04:00
For abbc need to get row 1 which have latest timestamp(2013-01-13 15:00:00) and i need row 2 with pbbb (2013-01-13 15:05:00) and row 3 dddd (2013-01-13 15:05:00). I have this timestamp data for each user in backend just need a proper query to fetch all those rows using timestamps.
Note: There could be multiple users with same timestamps, ex - if 10 users have same timestamp as abbc i will require all those users.
JPQL is picky about the syntax it allows. You may try using correlated subqueries here:
select e
from your_entity e
where e.timestamp = (select max(f.timestamp)
from your_entity f where f.user = e.user)
Try CTE + analytical function row_number()
with t1 as (
select id, testcase_id, user, timestamp,
row_number() over (partition by user order by timestamp desc) rno
from your_table)
select select id, testcase_id, user, timestamp
from t1
where rno = 1

Mysql time spent at work by specyfic user

I have a MySQL table like this:
+-----+----------+------------+--------------+-------------+
| id | user_id | added_on | status_enter | status_exit |
+-----+----------+------------+--------------+-------------+
Is it possible to count the time if the data is in other rows?
12:16:16 - 10:44:1
User Date Enter Exit
----------- -------------------- ------ ------
John 2021-06-25 10:44:15 1 0
John 2021-06-25 12:16:16 0 1
Not tested, but SHOULD get what you are looking for. The outer query is only looking for those where a person clocked IN. The 3rd column-based select is a correlated query to whatever the current user is and the ID is greater than the check-in, AND it is the check-out. So its possible a null value here if the person is still clocked-in. I would have an index on this table by (enter, user, exit, id) to help optimize the query.
select
tc.id,
tc.user,
tc.date,
( select min( tc2.date )
from TimeClockTable tc2
where tc.User = tc2.User
and tc.id < tc2.id
and tc2.enter = 0
and tc2.exit = 1 ) EndTime,
( select min( tc2.id )
from TimeClockTable tc2
where tc.User = tc2.User
and tc.id < tc2.id
and tc2.enter = 0
and tc2.exit = 1 ) EndTimeID
from
TimeClockTable tc
where
tc.enter = 1
FEEDBACK
If the date/time stamp is always going to be sequential with the ID as it is added, ie: ID #1234 on July 5 at 10:00am will ALWAYS be before #1235 on July 5 at 10:01am (you would never have an ID 1235 or higher that was BEFORE the date/time of ID #1234), then the above modification to the query should work for you. You are already getting the lowest date/time for the given user in comparison to the first, then calling it a second time to get the minimum ID would correlate to the same end time.
There you go:
SELECT T.user_id AS User,
CAST(T.added_on AS DATE) AS Date,
DATEDIFF(
HOUR,
MIN(T.added_on),
MAX(T.added_on)
) AS TotalWorkTime
FROM WorkTable AS T
GROUP BY T.user_id,
CAST(T.added_on AS DATE)

SQL: get current online player count using login/logout timestamp

I have a MySQL table that comprises uid, login/logout status flat, timestamp, for example:
uid flag time
123 login 10:00:00
123 logout 10:10:00
321 login 10:08:00
321 logout 10:18:00
Now I want to display online player count for every minute between 10:08 to 10:09. What is expected:
Minute current_player_cnt
10:07 1
10:08 2
10:09 2
I can export data as csv file and do this using python, but I want directly do this using sql and cannot find a function that could help.
You do not need to give the entire sql sentence, just give a function name will be fine. Any suggestion is appreciated.
One option is to join using a calendar table, e.g.
SELECT
t1.Minute,
COUNT(t2.uid) AS current_player_cnt
FROM
(
SELECT '10:07:00' AS Minute UNION ALL
SELECT '10:08:00' UNION ALL
SELECT '10:09:00'
) t1
LEFT JOIN
(
SELECT uid, MIN(time) AS login_time, MAX(time) AS logout_time
FROM yourTable
GROUP BY uid
) t2
ON t1.Minute BETWEEN t2.login_time AND t2.logout_time OR
(t1.Minute >= t2.login_time AND t2.login_time = t2.logout_time)
GROUP BY
t1.Minute;
Demo

how to get the latest record of loginevent from each user?

This question may already asked, but my question refers to two separate tables. I have only seen the answer when using same table with date row on it.
I have two tables, one is the user table and the other is login_log table.
I want to get the event from latest date record and from each user.
I have already made sql query, but cant understand how can I pick the max(date) from separate user.
SELECT s.username_id,s.date,s.event,m.username
FROM sys_log s join
users m
on s.username_id = m.id
id, username
---------
1 test
2 test2
id, username_id, date, event
------------------------------------------
1 1 1/1/2017 22:10:11 logout
2 1 1/1/2017 22:09:11 login
3 2 1/1/2017 21:05:11 logout
4 2 1/1/2017 21:02:11 login
the output should be like this
id, username, event ,date
-------------------------
1 test logout xxx
2 test2 logout xxx
Does this do what you want?
select s.username_id, s.date, s.event, m.username
from sys_log s join
users m
on s.sys_auth_id = m.id
where s.date = (select max(s2.date) from sys_log s2 where s2.sys_auth_id = s.sys_auth_id);

Counting entries within time range in MySQL

I have a table in my database where I am recording how long a user
is active or inactive. If a user switches from active to inactive or
vice versa (or changes any other attribute like address, etc) a new record is added. A simplified version looks like this:
UserID state state_from state_to
1 active 2016-12-14 2017-01-15
2 active 2016-12-14 2017-02-02
3 active 2017-01-01 NULL
1 inactive 2017-01-16 2017-03-05
2 inactive 2017-02-02 NULL
1 active 2017-03-06 NULL
I would like to count how many users had at some point the state "active", on a monthly basis. The desired output table for January till March would be:
date user_count
2017-01 3
2017-02 2
2017-03 2
For a specific timestamp (e.g. January 2017) I use the following query.
SET #stamp = '2017-01';
SELECT #stamp AS date, COUNT(UserID) AS user_count
FROM se_user
WHERE (state LIKE 'active' AND #stamp BETWEEN DATE_FORMAT(state_from,'%Y-%m') AND DATE_FORMAT(state_to,'%Y-%m') )
OR (state LIKE 'active' AND DATE_FORMAT(state_from,'%Y-%m') <= #stamp AND DATE_FORMAT(state_to,'%Y-%m') IS NULL);
My problem is, that I don't know how to do it for range of dates (say from January to March). Is there a way to do this?
Example database and table
-- Set up a test database
DROP DATABASE IF EXISTS se_toy_example;
CREATE DATABASE se_toy_example;
USE se_toy_example;
-- Create example table
DROP TABLE IF EXISTS se_user;
CREATE TABLE se_user (
UserID INT(10),
state VARCHAR(10),
state_from DATE,
state_to DATE
);
-- Populate table
INSERT INTO se_user (UserID,state,state_from,state_to)
VALUES (1,'active','2016-12-14','2017-01-15'),
(2,'active','2016-12-14','2017-02-02'),
(3,'active','2017-01-01',NULL),
(1,'inactive','2017-01-16','2017-03-05'),
(2,'inactive','2017-02-02',NULL),
(1,'active','2017-03-06',NULL);
You need a calendar_table to have the month date ranges, with dt_begin and dt_end for each month.
So your query for the current year become.
SQL DEMO
SELECT c.dt_begin, count(*)
FROM calendar_table c
JOIN se_user u
ON c.dt_begin <= COALESCE(u.state_to, curdate() )
AND c.dt_end >= u.state_from
WHERE dt_begin >= '2017-01-01'
AND dt_begin <= '2017-12-01'
AND state = 'active'
GROUP BY c.dt_begin
;
OUTPUT
NOTE: You can use LEFT JOIN if want the months with 0 activity.