Reuse result of IF condtion in true or false result expression - mysql

I have the following nested query:
SELECT `messages`.*,
IF((select `status` from messages_status
where messages_status.message_id = messages.id and user_id = 149) IS NULL,
'unread', messages_status.status) as `status`
FROM `messages`
What I would like to do, if there is no messages_status.status set (i.e. if it is NULL), it should return 'unread'. However, if it is set, is should return its value.
Currently, it returns an error: Unknown column 'messages_status.status' in 'field list'
Do you have any idea how to fix this?

You can't refer to the result of the if's condition in other places. You could repeat the query:
IF((select `status` from messages_status
where messages_status.message_id = messages.id and user_id = 149) IS NULL,
'unread',
(select `status` from messages_status
where messages_status.message_id = messages.id and user_id = 149))
as status
But it's probably clearer to use a join instead:
select m.*
, coalesce(ms.status, 'unknown')
from messages m
left join
messages_status ms
on ms.message_id = m.id
and ms.user_id = 149
The coalesce function produces the first of its arguments that is not null.

Related

Mysql count if id not null

I want to count unread messages from the response table. the problem is, when no message exists according to the id in the where statement, it will count 0 and returns one row. That row must not be returned. any suggestions how to fix this issue?
SELECT m.*, COUNT(mr.id) as total_unread
FROM `message` m
LEFT JOIN message_response mr ON (mr.message_id = m.id) AND mr.read = 0
WHERE m.performance_report_id = :id
above statement will return if no message is found.
NULL NULL NULL NULL NULL NULL NULL 0
put your m.performance_report_id = :id in ON Clause instead of where
SELECT m.*, COUNT(mr.id) as total_unread
FROM `message` m
LEFT JOIN message_response mr ON (mr.message_id = m.id) AND mr.read = 0
and m.performance_report_id = :id

Case when nested select = null then else

Okay so i didn't quite know what to call this post i might update the title later.
I have the following problem:
Say for instance you have the following calculating nested sql:
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`localhost`
SQL SECURITY DEFINER
VIEW `v_user_category_stat` AS
SELECT
(SELECT
SUM(MS.score) + (SELECT
SUM(UHMS.score)
FROM
User_has_module_score UHMS
RIGHT OUTER JOIN
module M ON M.id = UHMS.module_id
JOIN
Category C ON C.id = M.category_id
WHERE
UHMS.user_id = U.id)
FROM
Module_score MS
RIGHT OUTER JOIN
Module M ON M.id = MS.module_id
JOIN
Category C ON C.id = M.category_id
WHERE
MS.user_id = U.id) AS total_score,
U.id
FROM
User U
This gives me the wanted result which is:
# total_score, id
NULL, '2'
NULL, '7'
NULL, '8'
NULL, '9'
NULL, '10'
NULL, '11'
NULL, '12'
NULL, '13'
'13', '14'
Now i thought to my self i want to prettyfi this by making sure that if the value is null then it should be 0 (instead of null)
My question is how do you make a CASE that says if null THEN 0 ELSE normal?
Check the COALESCE function. In your case you will do this:
COALESCE(normal, 0)

Query and get three expected results

SELECT
(
`members`.`id`
SELECT COUNT(`members`.`id`) FROM `members` WHERE `gender` = 0 AS `Unknown`
SELECT COUNT(`members`.`id`) FROM `members` WHERE `gender` = 1 AS `Female`
SELECT COUNT(`members`.`id`) FROM `members` WHERE `gender` = 2 AS `Male`
) FROM `members` INNER JOIN `mapMember`
ON `mapMember`.`id` = `members`.`id`
WHERE `mapMember`.`mapper_id` = 3
My expected result:
Unknown Female Male
0 1 3
However I get SYNTAX error. Cant' figure out what's wrong.
I also tried:
SELECT COUNT(`members`.id) AS `members`, `gender`
FROM `members` INNER JOIN `mapMember`
ON `mapMember`.`id` = `members`.`id`
WHERE `mapMember`.`mapper_id` = 3 GROUP BY `gender` ORDER BY `gender` ASC
Which gives me almost the result I want to have, the only difference is If the there are no members with the given gender, there won't be a 0 result back. (no row that is) I always expect three rows back.
SELECT
sum(if (`gender` = 0, 1,0)) as `Unknown`,
sum(if (`gender` = 1, 1,0)) as `Female`,
sum(if (`gender` = 2, 1,0)) as `Male`
FROM `members` INNER JOIN `mapMember`
ON `mapMember`.`id` = `members`.`id`
WHERE `mapMember`.`mapper_id` = 3
SELECT * FROM
(
SELECT `members`.`id`,COUNT(`members`.`id`) AS `Unknown` FROM `members` WHERE `gender` = 0
UNION
SELECT `members`.`id`,COUNT(`members`.`id`) AS `Female` FROM `members` WHERE `gender` = 1
UNION
SELECT `members`.`id`,COUNT(`members`.`id`) AS `Male` FROM `members` WHERE `gender` = 2
) Z INNER JOIN `mapMember`
ON `mapMember`.`id` = `Z`.`id`
WHERE `mapMember`.`mapper_id` = 3
Others have given you solutions, so I mainly tell you where you went wrong with your own statement.
COUNT(column_name) simply counts records where column_name is not null. members.id is not null, so you simply count all records from members. You need a where clause instead limiting the counted records to the member id in question.
Sub queries must be in parentheses.
Here is your statement re-written. It is not good though, because you query the same table again and again. I just wanted to use your statement and only correct errors:
SELECT
`members`.`id`,
(SELECT COUNT(*) FROM `members` u WHERE `gender` = 0 AND u.id = members.id) AS `Unknown`
(SELECT COUNT(*) FROM `members` f WHERE `gender` = 1 AND f.id = members.id) AS `Female`
(SELECT COUNT(*) FROM `members` m WHERE `gender` = 2 AND m.id = members.id) AS `Male`
FROM `members` INNER JOIN `mapMember`
ON `mapMember`.`id` = `members`.`id`
WHERE `mapMember`.`mapper_id` = 3;
Now it's syntactically correct. However, as a member record has exactly one gender, you will always get records with 0-0-1 or 0-1-0 or 1-0-0. So you don't really want to select members and have the counts per member.
Here is a better statement querying the tables just once, counting over all records rather than per member and providing better readabilty by using an IN clause for mapmember. (You can as well replace the IN clause with an EXISTS clause, which is sometimes faster.)
select
sum( case when gender = 0 then 1 else 0 end ) as unknown,
sum( case when gender = 1 then 1 else 0 end ) as female,
sum( case when gender = 2 then 1 else 0 end ) as male
from members
where id in (select id from mapmember where mapper_id = 3);
(BTW: Is the mapmember id really a members id? It looks strange to have a table with a column named id and this not being the id of the table itself but the id of another table actually.)
EDIT: I just notice you use MySQL. There you have a boolean data type you can use:
select
sum( gender = 0 ) as unknown, sum( gender = 1 ) as female, sum( gender = 2 ) as male
from members
where id in (select id from mapmember where mapper_id = 3);
This is no longer standard SQL, because it uses an enhancement from MySQL.

Check in MySQL table if my ID exist in the results

How to check in MySQL table if my ID exist in the results and return TRUE, but this is a little complicated as I would like to check GROUP of records and not the last one from that GROUP, code below for the table and query which doesn't work, I would like to check if my $session_user_id exist in the GROUP OF auction_bid_item_id but not check last row as the last row is a WINNING ROW.
CREATE TABLE `auction_bids` (
`auction_bid_id` int(11) NOT NULL AUTO_INCREMENT,
`auction_bid_user_id` int(11) NOT NULL,
`auction_bid_seller_id` int(11) NOT NULL,
`auction_bid_item_id` int(11) NOT NULL,
PRIMARY KEY (`auction_bid_id`)
);
MySQL Query:
SELECT * FROM auction_bids
WHERE auction_bid_user_id = '$session_user_id'
GROUP BY auction_bid_item_id;
Join against a subselect which determines if the user is in that group.
Ie, the following will get you the bids and a field saying if the user is found.
SELECT auction_bids.*, IF(Sub1.auction_bid_item_id IS NULL, 'User not found', 'User found')
FROM auction_bids
LEFT OUTER JOIN
(
SELECT DISTINCT auction_bid_item_id
FROM auction_bids
WHERE auction_bid_user_id = '$session_user_id'
) Sub1
ON auction_bids.auction_bid_item_id = Sub1.auction_bid_item_id
GROUP BY auction_bids.auction_bid_item_id
EDIT - try this to try and ignore the latest bid
SELECT auction_bids.*, IF(Sub1.auction_bid_item_id IS NULL, 'User not found', 'User found')
FROM auction_bids
LEFT OUTER JOIN
(
SELECT DISTINCT auction_bids.auction_bid_item_id
FROM auction_bids
LEFT OUTER JOIN
(
SELECT auction_bid_item_id, MAX(auction_bid_id) AS LastBid
FROM auction_bids
GROUP BY auction_bid_item_id
) Sub2
ON auction_bids.auction_bid_item_id = Sub2.auction_bid_item_id
AND auction_bids.auction_bid_id = Sub2.LastBid
WHERE Sub2.auction_bid_item_id IS NULL
AND auction_bid_user_id = '$session_user_id'
) Sub1
ON auction_bids.auction_bid_item_id = Sub1.auction_bid_item_id
GROUP BY auction_bids.auction_bid_item_id
Something like this? (with php)
$id_exists = false;
$id = mysql_real_escape_string($_GET['id']);
$select = "SELECT auction_bid_id FROM auction_bids WHERE auction_bid_id ='$id'";
$result = mysql_query($select);
if(mysql_num_rows($result) > 0){
$id_exists = true;
}else{
$id_exists = false;
}

MySQL IFNULL, Alias and LEFT JOIN result an Unknown column error

This is my simplified query:
SELECT `student`.`id`, `student`.`firstname`, `student`.`lastname`,
IFNULL(`review`.`score`, '0') AS `adminreview_score`,
`reviewcolor`.`color` AS adminreview_color FROM (`student`)
LEFT JOIN `review` ON `review`.`student_id` = `student`.`id` AND
review.reviewtype_id = 13
LEFT JOIN `reviewcolor` ON `reviewcolor`.`score` = `adminreview_score`
WHERE `student`.`id` > '0'
And this is the error I get:
Error Number: 1054
Unknown column 'adminreview_score' in 'on clause'
Note that there may be no row in review table with the situation:
`review`.`student_id` = `student`.`id` AND review.reviewtype_id = 13
In this situation, I want adminreview_score to be set as 0, and I hope reviewcolor.color be NULL or empry ()
Thank you
Try this: (I replaced the alias with the actual expression. Note that aliases from the SELECT clause can't be used in the rest of the SQL expression.)
SELECT `student`.`id`, `student`.`firstname`, `student`.`lastname`,
IFNULL(`review`.`score`, '0') AS `adminreview_score`,
`reviewcolor`.`color` AS adminreview_color
FROM (`student`)
LEFT JOIN `review` ON `review`.`student_id` = `student`.`id` AND review.reviewtype_id = 13
LEFT JOIN `reviewcolor` ON `reviewcolor`.`score` = IFNULL(`review`.`score`, '0')
WHERE `student`.`id` > '0'
You can use a variable, try This
set #a:='';
SELECT `student`.`id`, `student`.`firstname`, `student`.`lastname`,
IFNULL(#a:=`review`.`score`, #a:=0),
`reviewcolor`.`color` AS adminreview_color FROM (`student`)
LEFT JOIN `review` ON `review`.`student_id` = `student`.`id` AND
review.reviewtype_id = 13
LEFT JOIN `reviewcolor` ON `reviewcolor`.`score` = #a
WHERE `student`.`id` > '0'