I have a table that looks like this:
user_id
datetime
activity
2
2022-01-10 12:00:00
Logout
1
2022-01-09 12:00:00
Login
3
2022-01-08 12:00:00
Login
3
2022-01-07 12:00:00
Register
2
2022-01-06 12:00:00
Login
1
2022-01-05 12:00:00
Register
If I query the table sorted by datetime DESC I will get the result like the above.
How can I extend the query so that I can get the results grouped by the user_id like below?
user_id
datetime
activity
2
2022-01-10 12:00:00
Logout
2
2022-01-06 12:00:00
Login
1
2022-01-09 12:00:00
Login
1
2022-01-05 12:00:00
Register
3
2022-01-08 12:00:00
Login
3
2022-01-07 12:00:00
Register
The logic is the records will be sorted by datetime DESC at first and when it encounters the user_id for the record, it will aggregate all records belonging to the user_id together and maintaining the datetime DESC sorting within the user_id group.
Use MAX() window function in the ORDER BY clause:
SELECT *
FROM tablename
ORDER BY MAX(datetime) OVER (PARTITION BY user_id) DESC,
user_id, -- just in case there are duplicate datetimes, remove this if the column datetime is unique
datetime DESC;
See the demo.
Related
EDIT: I have added the primary key, following the comment by #Strawberry
The aim is to return the number of current members, and also the number of past memberships, on any particular date/time.
For example, suppose we have
msid id start cancelled
1 1 2020-01-01 09:00:00 null
2 2 2020-01-01 09:00:00 2020-12-31 09:00:00
3 2 2021-01-01 09:00:00 null
4 3 2020-01-01 09:00:00 2020-06-30 09:00:00
5 3 2020-02-01 09:00:00 2020-06-30 09:00:00
6 3 2020-07-01 09:00:00 null
and we want to calculate the number of members at various times, which should return as follows
Datetime Current Past <Notes - not to be returned by the query>
2020-01-01 12:00:00 3 0 -- all 3 IDs have joined earlier on this date
2020-02-01 12:00:00 3 0 -- new membership for existing member (ID 3) is not counted
2020-06-30 12:00:00 2 1 -- ID 3 has cancelled earlier on this day
2020-07-01 12:00:00 3 0 -- ID 3 has re-joined earlier on this day
2020-12-31 12:00:00 2 1 -- ID 2 has cancelled earlier on this day
2021-01-01 12:00:00 3 0 -- ID 2 has re-joined earlier on this day
An ID may either be current or past, but never both. That is, if a past member re-joins, as in the case of ID 2 and 3 above, they become current members, and are no longer past members.
Also, a member may have multiple current memberships, but they can only be counted as a current member once, as in the case of ID 3 above.
How can this be achieved in MySQL ?
Here is a db<>fiddle with the above data
Test this:
WITH
cte1 AS ( SELECT start `timestamp` FROM dt
UNION
SELECT cancelled FROM dt WHERE cancelled IS NOT NULL ),
cte2 AS ( SELECT DISTINCT id
FROM dt )
SELECT cte1.`timestamp`, COUNT(DISTINCT dt.id) current, SUM(dt.id IS NULL) past
FROM cte1
CROSS JOIN cte2
LEFT JOIN dt ON cte1.`timestamp` >= dt.start
AND (cte1.`timestamp` < dt.cancelled OR dt.cancelled IS NULL)
AND cte2.id = dt.id
GROUP BY cte1.`timestamp`
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=942e4c97951ed0929e178134ef67ce69
I have a table where records will be getting inserted every 4 hours on a daily basis. If the record was not inserted for continuous 4 hours, I need to insert a log into another table. Below is the table schema.
Id DocPathid CreatedAt
1 1 2021-04-02 00:00:00
2 1 2021-04-02 04:00:00
3 1 2021-04-02 09:00:00
4 1 2021-04-02 12:00:00
5 1 2021-04-02 16:00:00
6 1 2021-04-02 20:00:00
7 1 2021-04-02 24:00:00
In the above case, there was no records inserted within a interval of 4hours (i.e. between 2021-04-02 04:00:00 & 2021-04-02 09:00:00). The query should return no. of failure count (in this case it is failed for 1 time).
Is there a way to achieve this in MySQL?
You can do something like this.
select count(1)
from (
select id, CreatedAt , timestampdiff(hour, CreatedAt
, lead(CreatedAt,1) over (partition by DocPathid order by CreatedAt) ) as hour
from Table1
) t
where hour >4
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=9b0c631145422dbccd2ea23f0a7d2011
I have this table
user_id activity dt
1 login 2020-01-01 08:00:00
1 logout 2020-01-01 20:00:00
2 home 2020-01-01 19:00:00
1 profile 2020-01-02 08:00:00
I need to insert last day for every user and the event of the last day is the last activity of that user. for example if user A logout on 2020-01-01 20:00:00 then you insert user A logout on 2020-01-02 00:00:00. the example is like in the last 3 rows of this table:
user_id activity dt
1 login 2020-01-01 08:00:00
1 logout 2020-01-01 20:00:00
2 home 2020-01-01 19:00:00
1 profile 2020-01-02 08:00:00
1 logout 2020-01-02 00:00:00
2 home 2020-01-02 00:00:00
1 profile 2020-01-03 00:00:00
on 2020-01-01 there is 2 user that have activity, so you have to input last activity of user 1 and 2 and the time is 2020-01-02 00:00:00.
I already search this solution on internet but can't find out the way to do it. All I have done is insert it manual one by one
In modern MySQL since version 8.0 you can use next approach:
insert into tbl
select distinct
user_id,
last_value(activity) over (partition by user_id, date(dt)),
date_add(date(dt), interval 1 day) dt
from tbl
order by dt
;
share SQL query
Hmmm . . . To get the last activity on each date with the appropriate new dt column:
select user_id, activity,
date(dt) + interval 1 day
from (select t.*,
row_number() over (partition by user_id, date(dt) order by dt desc) as seqnum
from t
) t
where seqnum = 1;
For a result set, you can union this to the existing table. If you want to actually modify the table, then insert these rows into the table.
id ref_id dates
1 1 2017-01-01 00:00:00
2 1 2017-01-31 00:00:00
3 2 2017-01-01 00:00:00
4 2 2017-01-31 00:00:00
5 3 2016-01-01 00:00:00
6 3 2016-01-31 00:00:00
Query will be like
SELECT * FROM table WHERE dates GROUP By ref_id
I would like to compare ref_id wise Start Date in 1st row & End Date in 2nd row should be between Current Date.
So output will be only those ref_id which are in between current date.
Output
ref_id
1
2
or GROUP_CONCAT of that 1,2
Would like to using single query without UNION.
Try this:
SELECT ref_id
FROM table
GROUP BY ref_id
HAVING NOW() BETWEEN MIN(dates) AND MAX(dates)
The query uses NOW in order to get the current date/time value. If this value lies within the interval defined by the minimum and maximum date value of a ref_id group, then this ref_id is returned by the query.
I select records and group them by date and uid(which is not the primary key), and I need to page those records by date, how can I do it?
For example:
uid date
1 2012-01-10
2 2012-01-10
3 2012-01-09
3 2012-01-09
3 2012-01-11
sql:
SELECT date, uid
FROM users
GROUP by date,`uid`
Results:
uid date
1 2012-01-10
2 2012-01-10
3 2012-01-09
3 2012-01-11
Because I need to page those record by date, if I use sql like:
SELECT date, uid
FROM users
GROUP by date,`uid`
LIMIT 0,2
then I just get the records like this:
uid date
1 2012-01-10
2 2012-01-10
. how can I page the record by date.
The results I want when page size is 2:
uid date
1 2012-01-10
2 2012-01-10
3 2012-01-09
SELECT date, uid
FROM users
WHERE date >= 'your date'
AND date < 'your date' LIMIT 0, 3