wrong count in query - mysql

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!

Related

Get authorized user now 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'

how to get data if value exist else return default

i have this two data from my database which is the only difference is their status
id | userId | status | dateCreated
1 | 1 | pending | 2019-02-09 22:11:11
2 | 1 | complete | 2019-02-10 10:40:20
what i wanted to do is to get the data with status complete if status complete exist based on the id else get the status pending if complete status not exist
i tried using SELECT CASE statement but what happens is it returns both pending and complete status
the reason why i didn't just update the 1st data is for reports purposes.
is there a way to get this?
here is my sample query.
SELECT userId,
CASE
WHEN status = 'completed' THEN "completed"
ELSE "pending"
END AS status
FROM tbltransaction where userId = '1'
With EXISTS:
SELECT userId,
CASE
WHEN EXISTS (SELECT 1 FROM tbltransaction WHERE userId = '1' AND status = 'completed') THEN 'completed'
ELSE 'pending'
END AS status
FROM tbltransaction where userId = '1'
Aggregation returns one row per user:
SELECT userId,
(CASE WHEN SUM(status = 'completed') > 0 THEN 'completed'
ELSE 'pending'
END) AS status
FROM tbltransaction
WHERE userId = 1
GROUP BY userId;
Alternatively, if you only care about one user, you could use:
SELECT 1 as userId,
(CASE WHEN EXISTS (SELECT 1
FROM tbltransaction t
WHERE t.userId = 1 AND
t.status = 'completed'
)
THEN 'completed'
ELSE 'pending'
END)
I might be wrong but from what you describe, it looks like you want the latest status for a given userId. I'm also assuming id is an Auto Increment column. If this is the case, then maybe you can try this
SELECT userId, status FROM tbltransaction tbl1
INNER JOIN
(
SELECT userId, max(id) as max_id
FROM tbltransaction
GROUP BY userId
) tbl2
ON tbl1.userId = tbl2.userId
AND tbl1.id = tbl2.max_id;
This would return the latest status for all users under the above assumptions.
Hope this helps! Cheers!

Get the student result from status when grouping in mysql

I have created a temporary table from records which looks like below. I want to group student using student id (stu_D). While grouping student result status will be PASSED if he passed all the subject and FAILED if he failed at least one.thanks in advanced
You can try below query -
SELECT stu_D
,stuName
,CASE
WHEN T2.CNT = 0
THEN 'passed'
ELSE 'failed'
END status
FROM (SELECT stu_D
,stuName
,COUNT(CASE
WHEN result = 'FAILED'
THEN 1
END) CNT
FROM T
GROUP BY stu_D
,stuname) T2
SELECT
T.stu_D, T.stuName, IF(T.number_of_failures>0, 'FAILED', 'PASSED') final_result
FROM
(SELECT
stu_D, stuName, COUNT(IF(result='FAILED', 1, NULL)) number_of_failures
FROM your_table
GROUP BY stu_D, stuName) T;
try this query
SELECT stu_Name,result
FROM `marks`
WHERE stu_D not in
(SELECT stu_D FROM marks WHERE result='FAILED')
GROUP BY stu_D

Change parameter in MySQL request SELECT

I am trying to change 'from_user' with a parameter from the other table and it doesn't work but when I am using the same table it works like a charm:
SELECT from_user, message_contents, message_read, to_user, date
FROM table1
WHERE date IN (
SELECT MAX( date )
FROM table1
WHERE to_user = 1 GROUP BY from_user
)
ORDER BY from_user ASC , date DESC
but this one just show one record but not all latest ones:
SELECT table2.`display_name`, message_contents, message_read, to_user, date
FROM table1, table2
WHERE table1.`from_user` = table2.`ID`
AND date IN ( SELECT MAX( date )
FROM table1
WHERE to_user = 1 GROUP BY from_user
)
ORDER BY from_user ASC , date DESC
Can anybody help to change 'from_user' with table2.display_name parameter but to get all recent records from mySQL?
You are joining two tables on table1.from_user = table2.id
So, if you don't want that table two to affect the number of rows than you can make a query like this:
SELECT
table1.from_user,
table2.`display_name`,
message_contents,
message_read,
to_user,
date
FROM table1
LEFT JOIN table2 ON table1.`from_user` = table2.`ID`
WHERE
date IN (SELECT MAX(date) FROM table1 WHERE to_user = 1 GROUP BY from_user)
ORDER BY from_user ASC , date DESC
I added also table1.from_user on the select clause which will help you see the from users which don't have a display name.

mysql 2 set of sum using groupby rollup

I have a query
select user_id,sum(hours),date, task_id from table where used_id = 'x' and date >='' and date<= '' group by user_id, date, task_id with roll up
The query works fine. But I also need to find a second sum(hours) where the group by order is changed.
select user_id,sum(hours),date, task_id from table where used_id = 'x' group by user_id,task_id
(The actual where condition is much longer.)
Is it possible to get both the sum in a single query since the where condition almost the same?
SELECT * FROM (
SELECT 1 AS list_id
, user_id
, sum(hours) AS total_hours
, `date`
, task_id
FROM table WHERE used_id = 'x' AND `date` BETWEEN #thisdate AND #thatdate
GROUP BY user_id, `date`, task_id /*WITH ROLLUP*/
UNION ALL
SELECT 2 AS list_id
, user_id
, sum(hours) AS total_hours
, `date`
, task_id
FROM table
WHERE used_id = 'x'
GROUP BY user_id,task_id WITH ROLLUP ) q
/*ORDER BY q.list_id, q.user_id, q.`date`, q.task_id*/
Depending on your needs, you should only need one with rollup, or two.