Get authorized user now mysql - mysql

I have table structure:
I need get last authorized user with status 'Signed in' without last status 'Signed off'. How I can do it?
I have a query:
SELECT * FROM vtiger_loginhistory WHERE status = 'Signed in' ORDER BY login_time DESC LIMIT 1
But this get me last authorized user admin, why? If he is Signed off. I need get Igor, because he is Signed in last.

You can try that: first select more recent row for each username and use JOIN or another SELECT to see if it's a "in" or "off"
EDIT: the concept is the same but corrected thanks to this answer
Version i don't fully understand: https://sqltest.net/#464377
SELECT *
FROM vtiger_loginhistory v_l
LEFT JOIN vtiger_loginhistory tmp
ON (v_l.user_name = tmp.user_name AND v_l.login_time < tmp.login_time)
WHERE tmp.login_time IS NULL AND v_l.status = 'Signed in'
ORDER BY v_l.login_time DESC LIMIT 1
Similar result with a subquery as I described (seems slower as explained in linked answer): https://sqltest.net/#464385
SELECT *
FROM vtiger_loginhistory v_l
INNER JOIN (SELECT user_name, MAX(tmp.login_time) AS maxlogintime
FROM vtiger_loginhistory tmp GROUP BY user_name
ORDER BY login_time DESC) tmp2
ON (v_l.login_time = tmp2.maxlogintime)
WHERE status = 'Signed in'
ORDER BY login_time DESC LIMIT 1
EDITED ORIGINAL NOT WORKING VERSION: (because GROUP BY keeps the first row met, so the oldest dates)
SELECT *
FROM (
SELECT *
FROM vtiger_loginhistory
GROUP BY user_name
ORDER BY login_time DESC
) as temp
WHERE status = 'Signed in'
ORDER BY login_time DESC LIMIT 1

You could check for username that is not IN the list for signed off too
SELECT *
FROM vtiger_loginhistory
WHERE status = 'Signed in'
AND username NOT IN (
select username
from vtiger_loginhistory
where status = 'Signed OFF'
)
ORDER BY login_time DESC LIMIT 1

you can try below way by using not exists
select t1.* from vtiger_loginhistory t1
where
status = 'Signed in'
and not exists ( select 1 from vtiger_loginhistory t2
where t2.user_name=t1.user_name
and status = 'Signed off')
order by STR_TO_DATE(login_time,'%Y%m%d %h%i') DESC LIMIT 1
i think your login_time column is not datetime

There are many Signed in and Signed off user, the admin has signed off but the last signed in is more recent than Igor.
There are 2 solutions for you :
Renew the flow, when user Signed off just update the status instead of create new record
Create top1signedoff temporary table first and select the other not in top1signedoff
CREATE TEMPORARY TABLE top1signedoff SELECT username FROM vtiger_loginhistory WHERE status = 'Signed off' ORDER BY login_time DESC LIMIT 1;
SELECT * FROM vtiger_loginhistory
WHERE status = 'Signed in'
and username Not IN (
SELECT username FROM top1signedoff
)
ORDER BY login_time DESC LIMIT 1

Following query should give you the desired result
SELECT t.login_id,t.user_name, t.logout_time,t.login_time,t.status
FROM vtiger_loginhistory t
WHERE t.login_id = (
SELECT MAX(t2.login_id)
FROM vtiger_loginhistory t2
WHERE t2.user_name = t.user_name
GROUP BY t2.user_name
)
AND t.status = 'Signed in';
What we are doing here..
in sub-query we are fetching last login_id for user
and in main query we are checking if the status for that login_id is 'Signed in'

Related

MySQL clause in where `case when`

I am trying to figure it out but no solution at all.
My query :
SELECT * FROM table
WHERE owner = 'user'
AND (
CASE WHEN status = 'NEW'
THEN status = 'NEW'
ELSE status IN ('CB','NA','NI','GC','FC')
END
)
ORDER BY RAND() DESC
LIMIT 1;
What I want to achieve is to show all records where status is NEW in an Random order limited by one row each, when no records NEW for the user the query needs to show the other statuses.
Thank you.
SELECT * FROM Table
WHERE owner = 'user'
AND (CASE WHEN (SELECT COUNT(*) FROM Table WHERE status = 'NEW') >= 1 THEN
status = 'NEW'
ELSE status IN ('CB','NA','NI','GC','FC')
END)
ORDER BY RAND() DESC
LIMIT 1;
Demo
http://sqlfiddle.com/#!9/09b1c8/1
What i think, you can simply
SELECT * FROM table
WHERE owner = 'user'
AND (
CASE WHEN status = 'NEW'
THEN status = 'NEW'
ELSE status IN ('CB','NA','NI','GC','FC')
END
)
ORDER BY RAND() DESC
LIMIT 1;
To
SELECT * FROM table
WHERE owner = 'user' AND status IN ('NEW','CB','NA','NI','GC','FC')
GROUP By some_id
ORDER BY RAND() DESC
LIMIT 1;
SELECT * FROM table
WHERE owner = 'user'
AND status IN ('NEW', 'CB','NA','NI','GC','FC')
ORDER BY status = 'NEW' DESC,
RAND() DESC
LIMIT 1;
Will give you a total of 1 row, giving preference to a random 'NEW'. If no 'NEW' rows, then a random one of the others.
(Please clarify your Question and provide sample output.)

MySQL UNION on same table with two WHERE clause

I have a table alerts
date | alert | status | sentDate | id
In this table, after I have sent the alert, I set the status to 'sent' and set the sent date. By default the status is 'not' (which means it has not been sent yet).
Now, I want to get the last sentDate, I can get this using the following query
SELECT sentDate FROM alerts WHERE id = someid AND status = 'sent' Order by date desc limit 1;
Also, I want to get the latest alert which has not been sent, I am using this query
SELECT date, alert FROM alerts WHERE id = someid AND status = 'not' order by date asc limit 1;
Is it possible to do this in one query? perhaps using UNION. I have tried to apply UNION/UNION ALL on these two queries but it gives me error.
Can anyone please help?
Thanks in advance.
SELECT
max(CASE WHEN status = 'sent' THEN DATE END) AS sentDate,
max(CASE WHEN status = 'not' THEN DATE END) AS notSentDate
FROM alerts WHERE id = someid
You can try above query.
It will help you.
You Can Try this :
SELECT MAX(t.sentDate) AS sentDate, MAX(t.date) AS date, MAX(alert) AS alert
FROM
(
SELECT MAX(sentDate) AS sentDate, "" AS date, "" AS alert
FROM alerts
WHERE id = someid
AND status = 'sent'
UNION
SELECT "" AS sentDate, date, alert
FROM alerts
WHERE id = someid
AND status = 'not'
) t
You could try this one
SELECT
(Select date from alerts where id= someid AND status='not'
ORDER by date DESC limit 1) latestNotSentDate,
(Select date from alerts where id= someid AND status='sent'
ORDER BY date DESC limit 1) latestSentDate;
The number of columns have to be the same in your queries, try this :
SELECT sentDate,'' FROM alerts WHERE id = 'id' AND status = 'sent' Order by date desc limit 1;
UNION
SELECT date, alert FROM alerts WHERE id = 'id' AND status = 'not' order by date asc limit 1;
In addition, i think the status is irrelevant, this information is given by the presence of a sentDate.
I think you can write :
SELECT sentDate,'' FROM alerts WHERE id = 'id' AND sentDate is not null Order by date desc limit 1;
UNION
SELECT date, alert FROM alerts WHERE id = 'id' AND sentDate is NULL order by date asc limit 1;

How to get Last and Secondlast Record from mysql table

From the above image i have n number of records with cat_id and sub_cat_id but in image only two are there.
so i want get the last and secondlast score_in_per value as named lastScore and latetsScore..
how can i retrieve that..?
SELECT
(SELECT score_in_per FROM tbl_student_skill_score ORDER BY date DESC LIMIT 2,0) as lastScore,
(SELECT score_in_per FROM tbl_student_skill_score ORDER BY date DESC LIMIT 1) as latetsScore
i am new to this complicated mysql logics..This what i have tried..
Example:
lets say one user email is inststudent#yopmail.com take the same test 2 times and the test is linked up with one category and sub category.
so the user will take the test any number of times...
from that records i want to get the last two records percentage.
If I understand you correctly; you want to select the two most recent results of a specific type of test taken by a specific student.
You don't use the LIMIT clause correctly. This is the correct syntax: LIMIT {[offset,] row_count | row_count OFFSET offset}. Also, you completely left out the where clause.
So the query should be:
SELECT
(SELECT score_in_per FROM tbl_student_skill_score
WHERE user_email = "email of the user you are interested in"
AND cat_id = categoryOfTestOfInterest
AND sub_cat_id = subcategoryOfTestOfInterest
ORDER BY date DESC LIMIT 1, 1
)AS lastScore,
(SELECT score_in_per FROM tbl_student_skill_score
WHERE user_email = "email of the user you are interested in"
AND cat_id = categoryOfTestOfInterest
AND sub_cat_id = subcategoryOfTestOfInterest
ORDER BY date DESC LIMIT 1
)AS latetsScore;
If a student can take the test multiple times a day (like your image suggests) than you should also order by id (supposing that the id is always greater for newer results) or better still, only by the id:
SELECT
(SELECT score_in_per FROM tbl_student_skill_score
WHERE user_email = "email of the user you are interested in"
AND cat_id = categoryOfTestOfInterest
AND sub_cat_id = subcategoryOfTestOfInterest
ORDER BY id DESC LIMIT 1, 1
)AS lastScore,
(SELECT score_in_per FROM tbl_student_skill_score
WHERE user_email = "email of the user you are interested in"
AND cat_id = categoryOfTestOfInterest
AND sub_cat_id = subcategoryOfTestOfInterest
ORDER BY id DESC LIMIT 1
)AS latetsScore;
One of the way of solving this problem is by using Partition By .
Step1: I have ranked the data for distinct cat_id and sub_cat_id in descending order of date by partition by.
Step2: I have used rank1 which is the latest score and merged it with rank2 which is the second last score
with chck as
(select
cat_id,sub_cat_id,score_in_per,date1,
row_number() over(partition by cat_id,sub_cat_id order by
cat_id,sub_cat_id,date1 desc) as row_num
from tbl)
select a.*,b.second_last_score from
(select cat_id,sub_cat_id,score_in_per,date1,row_num as last_score from chck where row_num=1) a
left join
(select cat_id,sub_cat_id,score_in_per,date1,row_num as second_last_score from chck where row_num=2) b
on a.cat_id = b.cat_id and a.sub_cat_id = b.sub_cat_id;
Let me know in case of any query.
SELECT
( SELECT score_in_per FROM tbl_student_skill_score WHERE cat_id=1 and sub_cat_id=5 ORDER BY date,id DESC LIMIT 1 ) AS latestScore,
( SELECT score_in_per FROM tbl_student_skill_score WHERE cat_id=1 and sub_cat_id=5 ORDER BY date,id DESC LIMIT 1,1 ) AS lastScore

Query to select all rows since last success

Given my following table structure:
I'm trying to build a query that will return the number of failed login attempts per IP since the last successful login of that same IP within the past hour.
For instance, you'll notice there are several failed attempts (0) from a single IP within the past hour, but since the last successful login (#145) there has only been 1 (#146), which is what I want returned.
This query should also be dynamic and return rows of grouped IPs.
So far this is what I have, but I think #ipa is returning NULL
SELECT COUNT(*) tries, #ipa := login_ip
FROM login_log
WHERE login_id > (
SELECT MAX(login_id)
FROM login_log
WHERE login_success = 1
AND login_ip = #ipa
)
AND login_success = 0
AND login_date > NOW() - 3600
GROUP BY login_ip
ORDER BY tries DESC;
Thanks
Alias the table and try it this way, as your #ipa variable is doing nothing for you:
SELECT COUNT(1) tries, l.login_ip
FROM login_log l
WHERE login_id > (
SELECT MAX(login_id)
FROM login_log l2
WHERE l2.login_success = 1
AND l2.login_ip = l.login_ip
)
AND login_success = 0
AND login_date > NOW() - 3600
GROUP BY login_ip
ORDER BY tries DESC;
Additionally, you can do this with a join:
select
count(1) tries,
log1.login_ip
from
login_log log1
inner join (
select
login_ip,
max(login_date) as max_date
from
login_log
where
login_success = 1
group by
login_ip
) log2 on
log1.login_ip = log2.login_ip
where
log1.login_success = 0
and log1.login_date > NOW() - 3600
and log1.login_date > log2.max_date
group by
login_ip
order by tries desc
You can try both ways and see which one is faster for you.

wrong count in query

I have a table whose structure is as follows:
id int
userid int
status enum ('pending','approved')
dop datetime
Data is as:
id userid status dop
1 24 pending 2011-02-14 06:41:32
2 24 pending 2011-02-15 23:02:45
When I fire the following query:
SELECT count( userid )
FROM t1
WHERE STATUS = 'pending'
GROUP BY userid
It's giving me count as '2', which is wrong, can anyone tell me what's wrong here? and how to get real count as 1
The group by statement is executed after the count. Use this instead:
SELECT count( DISTINCT userid )
FROM t1
WHERE STATUS = 'pending'
Do you want to count the number of user with status pending then?
SELECT count(userid)
FROM t1
WHERE STATUS = 'pending'
GROUP BY status, userid
Try to add the userid in the select clause :
SELECT userid, count( userid )
FROM t1
WHERE STATUS = 'pending'
GROUP BY userid
Maybe adding DISTINCT() on userid?
SELECT count( DISTINCT userid )
FROM t1
WHERE STATUS = 'pending'
GROUP BY userid
You sould use the COUNT(DISTINCT()) construction, it allow you to count the diferent values not NULL (docu)
Try this sentence:
SELECT count( DISTINCT( userid ) )
FROM t1
WHERE STATUS = 'pending'
GROUP BY userid
HTH!