MySQL: Case Query within a Case Query? - mysql

I have a query that gets unit count and it tagging if completed or not.
SELECT distinct location,
case when id is NULL then 'Not Started'
when '1' then 'Completed'
else 'In Progress' end as Remarks,
count(name) as CountName
FROM table
group by location,
case when id is NULL then 'Not Started'
when '1' then 'Completed'
else 'In Progress' end;
Result:
But I want to summarized this as below image:
Condition is when there are more that two(2) Remarks in Location it should be tagged as "In-progress" and sum the CountName. But when only one Remarks for a Location, gets the Remarks as its tagged.

Not sure on this (sample data would help), but try this:
SELECT Location,
case when count(id) > 1 then 'In Progress'
when max(id) is null then 'Not Started'
when max(id) = 1 then 'Completed'
else 'In Progress' end As Remarks,
count(name) as CountName
FROM table
GROUP BY location

Like you said, a case within a case:
select location,
case when count(distinct case when id is null then 'Not Started'
when id = '1' then 'Completed'
else 'In Progress' end) > 1
then 'In Progress'
else max(case when id is null then 'Not Started'
when id = '1' then 'Completed'
else 'In Progress' end)
end as remarks,
count(*) as CountName
from tbl
group by location
SQLFiddle Demo

Try This query:-
SELECT location,
if(count(1) > 1, 'In Progress', Remarks) Remarks,
sum(countName) countName
FROM location
group by location

Related

MySQL CASE , SUM, GROUP BY

I want sum of payment status from two differnt columns based on paymentstatus value - but this query returns null for sum. Why is it not working?
select payment_status,
CASE
WHEN 'PAID' THEN sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
select sum(CASE WHEN payment_status = 'PAID' THEN paid_amount else 0 end) as paid,
sum(CASE WHEN payment_status = 'Not Paid' THEN total_amount_due else 0 end) as due
from monthly_fee
If you want this conditionally, you need to include the column in the case:
select payment_status,
(case payment_status
when 'Paid' then sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
end)
from monthly_fee
group by payment_status;
This seems like a strange way to write the query, unless you really want two rows.
Your WHEN clauses aren't a condition.
I'd expect to see something like
select payment_status,
CASE
WHEN payment_status = 'PAID' THEN sum(paid_amount)
when payment_status = 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
You can try the following query:
select sum(if(payment_status = 'PAID', paid_amount, 0)
+ if(payment_status = 'Not Paid', total_amount_due, 0))
from monthly_fee
group by payment_status;

mysql join the 2 tables to produce following output

I have two tables: users and user_fingerprints.
How do I combine the two tables to produce the output?
I tried
select u.id, u.name,
case f.finger (when 0 then 'y' else 'n' end) '0',
case f.finger (when 1 then 'y' else 'n' end) '1',
case f.finger (when 2 then 'y' else 'n' end) '2',
case f.finger (when 3 then 'y' else 'n' end) '3',
case f.finger (when 4 then 'y' else 'n' end) '4',
case f.finger (when 5 then 'y' else 'n' end) '5',
case f.finger (when 6 then 'y' else 'n' end) '6'
from user u left join user_fingerprint f
on u.id=f.user_id
group by u.id
but the result will only take one row from same id and update it in the output table. when i use max function, it worked, but is there any way without using max?
Use an aggregation function:
select u.id, u.name,
max(case f.finger when 0 then 'y' else 'n' end) as '0',
max(case f.finger when 1 then 'y' else 'n' end) as '1',
max(case f.finger when 2 then 'y' else 'n' end) as '2',
max(case f.finger when 3 then 'y' else 'n' end) as '3',
max(case f.finger when 4 then 'y' else 'n' end) as '4',
max(case f.finger when 5 then 'y' else 'n' end) as '5',
max(case f.finger when 6 then 'y' else 'n' end) as '6'
from user u left join
user_fingerprint f
on u.id = f.user_id
group by u.id;
I would suggest that you reconsider using integers as column aliases. Looks doomed to be confusing . . . or worse, to cause hard to spot errors.
Also, note that max() works because 'y' > 'n'. There are other methods if you don't want to depend on that.
This also assumes that you want one summary row for each column. Otherwise you might want something like group_concat().
Not sure why don't you want to use function max, without max I think you can do it like this:
SELECT
u.id, u.name,
CASE WHEN LOCATE('0', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `0`,
CASE WHEN LOCATE('1', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `1`,
CASE WHEN LOCATE('2', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `2`,
CASE WHEN LOCATE('3', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `3`,
CASE WHEN LOCATE('4', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `4`,
CASE WHEN LOCATE('5', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `5`,
CASE WHEN LOCATE('6', GROUP_CONCAT(f.finger) THEN 'y' ELSE 'n' END `6`
FROM USER u
LEFT JOIN user_fingerprint f ON u.id = f.user_id
GROUP BY u.id
GROUP_CONCAT will concat all finger for each user and separated by comma, then LOCATE will return the index of first parameter in second parameter.

my mysql SELECT case can't return 3 columns

I'm trying to return 3 columns with the query below. the current query works fine.
SELECT cat, COUNT(*) as count FROM
(SELECT case WHEN `cat_type` = 'PREMIUM' then '1'
WHEN `cat_type` = 'NOT PREMIUM' then '2'
WHEN `cat_type` = 'GOLD' then '3'
WHEN `cat_type` = 'EXECUTIVE' then '4'
WHEN `cat_type` = 'NOT PROVIDED' then '-1'
else '-2'
end AS cat FROM `ab` AS s
JOIN `make` AS m
WHERE s.make_code = m.make_code
) AS someRandomAliasHere
GROUP BY cat
ORDER BY CAST(cat AS UNSIGNED) ASC
when i try and return another column cat_type i get an error
SELECT cat, cat_type, COUNT(*) as count FROM ....
The error i get is
#1054 - Unknown column 'cat_type' in 'field list'
but cat_type does exist in my ab table. any idea what i'm missing? Thanks
Your cat_type exists in ab table.
But your ab table does not exists in your main select.
It only exists within the sub query which returns someRandomAliasHere to you.
So you should likely select cat_type from the same select as you select your cases.
Then you should have access to it, but it would then likely mess with your group by / count.
You'll properly need a more advanced query for what you're after.
You need to include cat_type in the subquery. I would recommend:
SELECT cat, cat_type, COUNT(*) as count
FROM (SELECT (case WHEN `cat_type` = 'PREMIUM' then 1
WHEN `cat_type` = 'NOT PREMIUM' then 2
WHEN `cat_type` = 'GOLD' then 3
WHEN `cat_type` = 'EXECUTIVE' then 4
WHEN `cat_type` = 'NOT PROVIDED' then -1
else -2
end) AS cat, *
FROM `ab` AS s JOIN
`make` AS m
USING (make_code)
) AS someRandomAliasHere
GROUP BY cat, cat_type
ORDER BY abs(cat) asc
Note the following:
Added * to the subquery to capture all the columns.
Changed the join syntax. Not only are explicit joins better but the using clause allows the use of * without having to worry about duplicate names among the joined column.
Removed the single quotes from the constant values for cat. You are treating these as numbers in the order by, so use numbers for the values.
Changed the order by to abs() rather than casting to unsigned. However, do you really want unsigned here?
You're not selecting cat_type into someRandomAliasHere, hence it's not available to your main select. This should fix it:
SELECT cat, cat_type, COUNT(*) as count FROM
(SELECT case WHEN `cat_type` = 'PREMIUM' then '1'
WHEN `cat_type` = 'NOT PREMIUM' then '2'
WHEN `cat_type` = 'GOLD' then '3'
WHEN `cat_type` = 'EXECUTIVE' then '4'
WHEN `cat_type` = 'NOT PROVIDED' then '-1'
else '-2'
end AS cat, cat_type FROM `ab` AS s
JOIN `make` AS m
WHERE s.make_code = m.make_code
) AS someRandomAliasHere
GROUP BY cat, cat_type
ORDER BY CAST(cat AS UNSIGNED) ASC
You needed to include the column in subquery first and then reference that using the table.col
Try below
SELECT someRandomAliasHere.cat_type, cat, COUNT(*) as count FROM
(SELECT cat_type, case WHEN `cat_type` = 'PREMIUM' then '1'
WHEN `cat_type` = 'NOT PREMIUM' then '2'
WHEN `cat_type` = 'GOLD' then '3'
WHEN `cat_type` = 'EXECUTIVE' then '4'
WHEN `cat_type` = 'NOT PROVIDED' then '-1'
else '-2'
end AS cat FROM `ab` AS s
JOIN `make` AS m
WHERE s.make_code = m.make_code
) AS someRandomAliasHere
GROUP BY cat
ORDER BY CAST(cat AS UNSIGNED) ASC
You need to also select the column cat_type, so that someRandomAliasHere owns the column.
SELECT cat, cat_type, COUNT(*) as count FROM
(SELECT case WHEN `cat_type` = 'PREMIUM' then '1'
WHEN `cat_type` = 'NOT PREMIUM' then '2'
WHEN `cat_type` = 'GOLD' then '3'
WHEN `cat_type` = 'EXECUTIVE' then '4'
WHEN `cat_type` = 'NOT PROVIDED' then '-1'
else '-2'
end AS cat, cat_type FROM `ab` AS s
JOIN `make` AS m
WHERE s.make_code = m.make_code
) AS someRandomAliasHere
GROUP BY cat, cat_type
ORDER BY CAST(cat AS UNSIGNED) ASC
Dont forget to add cat_type in GROUP BY too.

Compare columns from SUM(CASE...END) in the same query

I'm trying to add a column named Ready to my query that checks if the sum of Complete is = to the sum of Total and places 'Y' if True and 'N' if FALSE.
Here is my query that works producing 4 columns
SELECT pc.Sub,
SUM(CASE WHEN `SheetStatus` LIKE 'Complete' THEN 1 ELSE 0 END) AS 'Complete',
SUM(CASE WHEN `SheetStatus` LIKE 'Not started' THEN 1 ELSE 0 END) AS 'Not Started',
SUM(CASE WHEN `CheckSheet` LIKE '%' THEN 1 ELSE 0 END) AS 'Total'
FROM `pc`
Group By pc.Sub WITH ROLLUP
I just cant figure out how to create the extra column if it is possible at all.
Regards
Try outer SELECT
SELECT `Complete`,
`Not Started`,
`Total`,
CASE WHEN `Complete` = `Total` THEN 'Y' ELSE 'N' END `Ready`
FROM (
SELECT pc.Sub,
SUM(CASE WHEN `SheetStatus` LIKE 'Complete' THEN 1 ELSE 0 END) AS `Complete`,
SUM(CASE WHEN `SheetStatus` LIKE 'Not started' THEN 1 ELSE 0 END) AS `Not Started`,
SUM(CASE WHEN `CheckSheet` LIKE '%' THEN 1 ELSE 0 END) AS `Total`
FROM `pc`
GROUP BY pc.Sub WITH ROLLUP) t
Try this:
SELECT pc.Sub,
SUM(IF(`SheetStatus`='Complete',1,0) AS 'Complete',
SUM(IF(`SheetStatus`='Not started',1,0) AS 'Not Started',
SUM(IF(`CheckSheet` LIKE '%',1,0) AS 'Total'
IF(SUM(IF(`CheckSheet` LIKE '%',1,0) = SUM(IF(`SheetStatus`='Complete',1,0),"Y","N") AS Ready
FROM `pc`
Group By pc.Sub WITH ROLLUP

SQL - Giving AS keyword in UPDATE Statement

I have the following UPDATE statement:
update MESSAGES set status=
(select (CASE
WHEN from_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'S'
WHEN status='R'
THEN 'D'
END)
WHEN to_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'R'
WHEN status='S'
THEN 'D'
END)
END)
as status_value)
where primary_key='236499681204'
and status_value not null ;
The problem with this query is, at the last line, status_value is not recognized. If I remove the last comparison, and status_value not null, it works. I dint expect the above version to work, but could someone tell me an alternative that would achieve the same?
Is there a way I can use the AS keyword in the UPDATE query to define the variable status_value?
Edit
The actual requirement is not just that i check if status_value is null, but also that I dont perform any update if it is null
Try to add ELSE STATUS and remove and status_value not null:
update MESSAGES set status=
(select (CASE
WHEN from_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'S'
WHEN status='R'
THEN 'D'
END)
WHEN to_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'R'
WHEN status='S'
THEN 'D'
END)
ELSE STATUS
END)
as status_value)
where primary_key='236499681204';
You can also try to use view
create view MyView as
select (CASE
WHEN from_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'S'
WHEN status='R'
THEN 'D'
END)
WHEN to_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'R'
WHEN status='S'
THEN 'D'
END)
END)
as status_value;
update MESSAGES set status= mv.status_value
from MyView mv
where primary_key='236499681204'
and mv.status_value is null
or you can use case in condition
update MESSAGES set status=
(select (CASE
WHEN from_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'S'
WHEN status='R'
THEN 'D'
END)
WHEN to_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'R'
WHEN status='S'
THEN 'D'
END)
END)
as status_value)
where primary_key='236499681204'
and CASE
WHEN from_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'S'
WHEN status='R'
THEN 'D'
END)
WHEN to_id='111111111'
THEN (CASE
WHEN status='A'
THEN 'R'
WHEN status='S'
THEN 'D'
END)
END is not null;
assuming all you want is to get rid of the null, you can do this:
update MESSAGES set status=
IFNULL(
(CASE WHEN from_id='111111111' THEN
(CASE WHEN status='A' THEN 'S'
WHEN status='R' THEN 'D' END)
WHEN to_id='111111111' THEN
(CASE WHEN status='A' THEN 'R'
WHEN status='S' THEN 'D' END) END),
status)
where primary_key='236499681204' ;
It seems to me that you're trying to do a sub-query for the update statement, when I don't think it's really all that necessary.
You can simplify the query a bit like this:
UPDATE MESSAGES
SET status = CASE
WHEN
(from_id='111111111' AND status='A') THEN 'S'
WHEN
(to_id ='111111111' AND status='A') THEN 'R'
WHEN
(from_id ='111111111' AND status='R') OR
(to_id ='111111111' AND status='S') THEN 'D'
ELSE status
END
WHERE priamry_key = '236499681204'