We have a log table where user processes log entries ( success
/ failure
/ timeout
) each time they run. For eg
+----+----------+---------+
| id | username | status |
+----+----------+---------+
| 1 | saqib | success |
| 2 | mary | timeout |
| 3 | scott | timeout |
| 4 | saqib | success |
| 5 | mary | timeout |
| 6 | scott | timeout |
| 7 | saqib | timeout |
| 8 | mary | timeout |
| 9 | scott | timeout |
+----+----------+---------+
We would like to get a usernames which have had a success in the past the but the latest entry for them was a timeout. (saqib in the above example)
Is there single query that can do this? Right now we are doing this using a PHP script, but would like to use mySQL query for this.
Thanks
You can retrieve the latest id
for each username
and then JOIN
it with the original table checking if there were entries for each user with status
success
and id
less then maximum.
SELECT t.*
FROM ( SELECT username
, MAX(id) as ind
FROM tbl
GROUP BY username
) x JOIN tbl t ON t.username = x.username
AND t.id = x.ind
AND t.status IN ('timeout', 'failure')
AND EXISTS ( SELECT *
FROM tbl
WHERE username = x.username
AND id < x.ind
AND status = 'success'
)
SELECT DISTINCT m1.username
FROM
(
SELECT s1.username, s1.ids
FROM
(
SELECT username, MAX(id) as ids
FROM MyTable
GROUP BY username
) AS s1
INNER JOIN MyTable AS s2
ON s1.ids = s2.id
WHERE s2.status = 'timeout'
) AS m1
INNER JOIN MyTable m2 ON m1.username = m2.username
AND m2.status = 'success'
I would use exists for this problem. Exists are nice because they generally are faster than joining to the table. Unrelated, but I would recommend using a time stamp as opposed to relying on the id number.
Select username
From table t1
Where t1.status = 'timeout'
and exists (Select 1
From table t2
Where t1.username = t2.username
and t2.status = 'success'
Limit 1)
and not exists (Select 1
From table t3
Where t3.username = t1.username
and t3.id > t1.id
Limit 1);
You can join the table to itself:
SELECT GROUP_CONCAT(CONCAT_WS(' -> ', a.id, b.id) SEPARATOR ','), a.username
FROM t a
JOIN t b USING (username)
WHERE b.id > a.id
AND (a.status = 'success'
AND b.status = 'timeout')
GROUP BY a.username;
This shows all pairs of previous success to later timeout.
SELECT
UserName, max(id)
FROM TABLE
WHERE
UserName IN (SELECT UserName from Table where Status = 'Success')
GROUP BY UserName
Having MAX(id) = (select max(id) from username where status = 'timeout')
You can do so by joining 2 subqueries 1 for the maximum id per user with success status which will satisfy the condition which have had a success in the past and 2 for the max id to get users with latest timeout last comparison part t1.id < t2.id
will satisfy the user should have success in past
select * from
(select `username`,max(id) id
from t
where `status` ='success'
group by `username`
) t1
join
(
select `username`,max(id) id
from t
where `status` ='timeout'
group by `username`
) t2
on(t1.username = t2.username)
where t1.id < t2.id
Another solution this will be much cleaner bu just using one query with max and case
select
username,
max(case when `status` ='success' then id else 0 end) success,
max(case when `status` ='timeout' then id else 0 end) timeout
from t
group by username
having timeout > success
and success > 0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.