need absent and present count with month name - mysql

I need a month name with absent and present count. This is my database query:
SELECT sid,COUNT(CASE WHEN STATUS ='A' THEN 1 END) AS absent_count,COUNT(CASE WHEN STATUS ='P' THEN 1 END) AS present_count,
MONTHNAME(attendance_date) AS `Month_Name`
FROM attendance
WHERE SID = '2'
AND campus_id = 2
GROUP BY sid;

There's no point in group by sid - it will always be '2', as per your where clause. Instead, since you want to count per month name, that should appear in the group by clause:
SELECT MONTHNAME(attendance_date) AS `Month_Name`,
COUNT(CASE WHEN STATUS ='A' THEN 1 END) AS absent_count,
COUNT(CASE WHEN STATUS ='P' THEN 1 END) AS present_count,
FROM attendance
WHERE sid = '2' AND campus_id = 2
GROUP BY MONTHNAME(attendance_date);

Related

Join not summing CASE WHEN

What I'm looking to do is show my current performance for this month, compared with expected scheduled wins to come in and then display the total expected amount, by product type.
For clarity, I have two sub-products that I'm grouping under the same name.
My issue is that for my 'Charged' amount, it's keeping the two sub-products separate, where as the 'Scheduled' amount is working fine.
The table should look like:
Type | Charged | Scheduled | Expected
A 3 2 5
B 1 1 2
What's actually showing is:
Type | Charged | Scheduled | Expected
A 2 1 3
A 1 1 2
B 1 1 2
The code is as follows:
select
t2.product,
t1.Charged,
t2.Scheduled,
t1.charged + t2.scheduled as 'expected'
from(
select
case
when user_type = 'a1' then 'a'
when user_type = 'a2' then 'a'
else 'b'
end as 'Type',
SUM(charged) as 'Scheduled'
from
table
where
month(date) = month(now())
and
year(date) = year(now())
and status like 'scheduled'
group by 1
order by 2 desc) t2 join
(select
case
when user_type = 'a1' then 'a'
when user_type = 'a2' then 'a'
else 'b'
end as 'Type',
sum(charged) as 'Charged'
FROM table
WHERE (status = 'Complete'
AND str_to_date(concat(date_format(date, '%Y-%m'), '-01'), '%Y-%m-%d') = str_to_date(concat(date_format(now(), '%Y-%m'), '-01'), '%Y-%m-%d'))
GROUP BY user_type
ORDER BY user_type ASC) as t1 on t1.type = t2.type
I appreciate I might not be explaining this incredibly well (and that my code is probably quite clunky - I'm still fairly new!) so any help/direction would be appreciated.
Thanks!
Just some suggestion
you have a column product in main select but you have type in subquery and not product
you should not use sigle quote around column name
ad you have group by user_type but you need group by type for charged
select
t2.type,
t1.Charged,
t2.Scheduled,
t1.charged + t2.scheduled as 'expected'
from(
select
case
when user_type = 'a1' then 'a'
when user_type = 'a2' then 'a'
else 'b'
end as Type,
SUM(charged) as Scheduled
from
table
where
month(date) = month(now())
and
year(date) = year(now())
and status like 'scheduled'
group by 1
order by 2 desc) t2 join
(select
case
when user_type = 'a1' then 'a'
when user_type = 'a2' then 'a'
else 'b'
end as Type,
sum(charged) as Charged
FROM table
WHERE (status = 'Complete'
AND str_to_date(concat(date_format(date, '%Y-%m'), '-01'), '%Y-%m-%d') = str_to_date(concat(date_format(now(), '%Y-%m'), '-01'), '%Y-%m-%d'))
GROUP BY Type
ORDER BY Type ASC) as t1 on t1.type = t2.type

How to minimize sql query

I have a booking table in MySQL database where I need to get 3 data.
1) Total Booking
2) Pending Booking ( where is_confirm = 1 )
3) Complete Booking ( where is_confirm = 0 )
Now, I am writing 3 separate query to get this but how can I get it using 1 query?
current query:
$booking = new Admin;
$booking->rowQuery("SELECT count(bid) AS totalBooking FROM booking");
$bookingData = $booking->result->fetch_assoc();
$totalBooking = $bookingData['totalBooking'];
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 1 ");
$completeBooking = $booking->rows;
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 0 ");
$pendingBooking = $booking->rows;
you can use case sql . Try this:
SELECT
COUNT(CASE WHEN is_confirm = 1 THEN 1 END) AS confirmCount,
COUNT(CASE WHEN is_confirm = 0 THEN 1 END) AS noconfirmCount,
COUNT(*) AS total
FROM booking;
SELECT count(bid) AS totalBooking FROM booking
UNION
SELECT bid FROM booking
WHERE is_confirm=1
UNION
SELECT bid FROM booking
WHERE is_confirm=0
Aggregate functions usually skip nulls, including group_concat. If you don't mind explodeing the result string later, you could use case expressions to get the total bookings and coma-delimited strings for the IDs:
SELECT COUNT(bid) AS totalBooking,
GROUP_CONCAT(CASE is_confirm WHEN 1 THEN bid END) AS pendingBookings,
GROUP_CONCAT(CASE is_confirm WHEN 0 THEN bid END) AS completeBookings
FROM booking

Get both results with one query

I want to get results for likes by a specific user-id and all likes and dislikes of a specific page id.
My structure looks like this:
`pages`: (id, title)
`pages_likes`: (id, page_id, uid, status)
If the status is -1 it's a dislike of a specific page, if it's 1 it's a like.
So, to get all likes this is my query:
SELECT COUNT(id) FROM pages_likes WHERE status = '1'
But now I also want to get if user-id 3 for example likes this page with
SELECT COUNT(id) FROM pages_likes WHERE status = '1' AND uid='3'
How can I achieve both in one query? I guess there has to be changed something right after the SELECT statement?
If you want to do this in a single query, use conditional aggregation:
SELECT SUM(CASE WHEN uid = '3' THEN 1 ELSE 0 END) AS threeLikes,
SUM(CASE WHEN uid <> '3' THEN 1 ELSE 0 END) AS otherLikes
FROM pages_likes
WHERE status = '1'
Another option would be to use a UNION, cf. the answer given by #bernie
Update:
If you want page likes and dislikes in the same query, you can try:
SELECT SUM(CASE WHEN uid = '3' AND status = '1' THEN 1 ELSE 0 END) AS threeLikes,
SUM(CASE WHEN uid <> '3' AND status = '1' THEN 1 ELSE 0 END) AS otherLikes
SUM(CASE WHEN uid = '3' AND status = '0' THEN 1 ELSE 0 END) AS threeDislikes,
SUM(CASE WHEN uid <> '3' AND status = '0' THEN 1 ELSE 0 END) AS otherDisikes
FROM pages_likes
I think this would work:
SELECT '' user, COUNT(id) likes
FROM pages_likes
WHERE status = '1'
GROUP BY 1
UNION ALL
SELECT uid user, COUNT(id) likes
FROM pages_likes
WHERE status = '1' AND uid='3'
GROUP BY 1
I would do it this way:
SELECT COUNT(*) AS total_likes, SUM(uid=3) AS uid3_likes
FROM pages_likes
WHERE status=1 AND page_id=1234
Re your comment:
Here's an example of showing total likes, and total dislikes. It's similar to the answer from #TimBiegeleisen.
SELECT SUM(status=1) AS total_likes,
SUM(CASE WHEN uid=3 AND status=1 THEN 1 END) AS uid3_likes
SUM(CASE WHEN uid=3 AND status=-1 THEN 1 END) AS uid3_dislikes
FROM pages_likes
WHERE page_id=1234

SQL using CASE in count and group by

I'm using CASE to categorize data in the table and count them but the results aren't accurate
live demo [here]
select DATE(date) as day, count(*),
count(distinct case when name = 'fruit' then 1 else 0 end) as fruits,
count(distinct case when name = 'vege' then 1 else 0 end) as vege,
count(distinct case when name = 'sweets' then 1 else 0 end) as sweets
from food
group by day
with rollup
I'm not sure if the issue is with CASE or in the string matching = because there's no 'sweets' still it counts 1?
any pointers I'd be grateful
Your problem is that COUNT counts every result that is not NULL. In your case you are using:
COUNT(distinct case when name = 'sweets' then 1 else 0 end)
So, when the name is not sweets, it counts the 0. Furthermore, since you are using DISTINCT, it counts just one or two values. You should either use SUM or remove the DISTINCT and the ELSE 0:
SELECT DATE(date) as day,
COUNT(*),
SUM(CASE WHEN name = 'fruit' THEN 1 ELSE 0 END) as fruits,
SUM(CASE WHEN name = 'vege' THEN 1 ELSE 0 END) as vege,
SUM(CASE WHEN name = 'sweets' THEN 1 ELSE 0 END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Or:
SELECT DATE(date) as day,
COUNT(*),
COUNT(CASE WHEN name = 'fruit' THEN 1 ELSE NULL END) as fruits,
COUNT(CASE WHEN name = 'vege' THEN 1 ELSE NULL END) as vege,
COUNT(CASE WHEN name = 'sweets' THEN 1 ELSE NULL END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Here is a modified sqlfiddle.
You can't group by an alias. You have to group by the expression.
group by date(date)
You can group on an Alias:
SELECT
FROM_UNIXTIME(UnixTimeField, '%Y') AS 'Year'
,FROM_UNIXTIME(UnixTimeField, '%m') AS 'Month'
FROM table p
GROUP BY Year, Month

Sum record between two dates for different users in mysql query Issue

I have two tables lead and lead_details. There is a field status. If status=1 is open, status=2 is close and status=3 is not specified.
I want to find sum of all Open,close and not specified for each user/agent.
Here is what I tried but it give me wrong data
select agent_id,
type,
status,
created_date,
category_id,
sum(case when status = 2 then val else 0 end) as closed1,
sum(case when status = 1 then val else 0 end) as opened1,
sum(case when status = 3 then val else 0 end) as notspecefied1
from ( select l.agent_id,
l.type,
ld.category_id,
l.status,
l.created_date,
count(*) as val
from crm_leads l,
crm_leads_details ld
where l.id=ld.lead_id AND
status in (2, 1, 3)
GROUP BY status, agent_id
) t
WHERE created_date BETWEEN '2013-8-2' AND '2013-9-2'
GROUP BY agent_id
You need to put the WHERE created_date clause in the subquery.
select agent_id,type,status,created_date,category_id,
sum(case when status = 2 then val else 0 end) as closed1,
sum(case when status = 1 then val else 0 end) as opened1,
sum(case when status = 3 then val else 0 end) as notspecefied1
from ( select l.agent_id,l.type,ld.category_id,l.status,l.created_date,
count(*) as val from crm_leads l JOIN crm_leads_details ld
ON l.id=ld.lead_id
WHERE created_date BETWEEN '2013-8-2' AND '2013-9-2' AND status in (2, 1, 3)
GROUP BY status, agent_id ) t
GROUP BY agent_id
Note that the created_date in the result will just be a randomly selected date in the period for each agent.