aggregating values by month, Group by statement in mysql - mysql

I have a question on how to group the following statement into months.
Database is MYSQL
Desired result is:
DRNAME, Jan, Feb, Mar, April, May ,June
SISHEN, 0, 0, 100, 250, 450, 500, 0
Result I get is:
DRNAME, Jan, Feb, Mar, April, May ,June
SISHEN, 0, 0, 100, 0, 0, 0,0
SISHEN, 0, 0,0,250,0,0,0
SISHEN, 0, 0, 0,0 , 450, 0, 0
query is
select drname,
case when month(loaddate) = 1 then sum(drvalue) end as 'Jan',<br>
case when month(loaddate) = 2 then sum(drvalue) end as 'Feb',<br>
case when month(loaddate) = 3 then sum(drvalue) end as 'March',<br>
case when month(loaddate) = 4 then sum(drvalue) end as 'April',<br>
case when month(loaddate) = 5 then sum(drvalue) end as 'May',<br>
case when month(loaddate) = 6 then sum(drvalue) end as 'June'<br>
from tblloadschedule<br>
where cancelloadflag = 'N' and drname like 'sish%'<br>
group by drname,month(loaddate)

You need to remove month(loaddate) from the group by clause and then use conditional aggregation instead:
select drname,
sum(case when month(loaddate) = 1 then drvalue else 0 end) as 'Jan',
sum(case when month(loaddate) = 2 then drvalue else 0 end) as 'Feb',
sum(case when month(loaddate) = 3 then drvalue else 0 end) as 'March',
sum(case when month(loaddate) = 4 then drvalue else 0 end) as 'April',
sum(case when month(loaddate) = 5 then drvalue else 0 end) as 'May',
sum(case when month(loaddate) = 6 then drvalue else 0 end) as 'June'
from tblloadschedule
where cancelloadflag = 'N' and drname like 'sish%'
group by drname

Modify your query to take aggregates of the conditional CASE expressions:
SELECT
drname,
SUM(CASE WHEN MONTH(loaddate) = 1 THEN drvalue END) AS Jan,
SUM(CASE WHEN MONTH(loaddate) = 2 THEN drvalue END) AS Feb,
SUM(CASE WHEN MONTH(loaddate) = 3 THEN drvalue END) AS March,
SUM(CASE WHEN MONTH(loaddate) = 4 THEN drvalue END) AS April,
sum(CASE WHEN MONTH(loaddate) = 5 THEN drvalue END) AS May,
sum(CASE WHEN MONTH(loaddate) = 6 THEN drvalue END) AS June
FROM tblloadschedule
WHERE
cancelloadflag = 'N' AND drname LIKE 'sish%'
GROUP BY
drname;

You don't need case which is expensive:
select drname,
sum(if(month(loaddate) = 1 ,drvalue,0) as 'Jan',
sum(if(month(loaddate) = 2 , drvalue ,0) as 'Feb',
sum(if(month(loaddate) = 3 , drvalue ,0) as 'March',
sum(if(month(loaddate) = 4 , drvalue ,0) as 'April',
sum(if(month(loaddate) = 5 , drvalue ,0) as 'May',
sum(if(month(loaddate) = 6 , drvalue ,0) as 'June'
from tblloadschedule
where cancelloadflag = 'N' and drname like 'sish%'
group by drname
EDIT without use of IF:
select drname,
sum((month(loaddate) = 1 ) * drvalue) as 'Jan',
sum((month(loaddate) = 2 ) * drvalue) as 'Feb',
sum((month(loaddate) = 3 ) * drvalue) as 'March',
sum((month(loaddate) = 4 ) * drvalue) as 'April',
sum((month(loaddate) = 5 ) * drvalue) as 'May',
sum((month(loaddate) = 6 ) * drvalue) as 'June'
from tblloadschedule
where cancelloadflag = 'N' and drname like 'sish%'
group by drname

The method from A. Colonna with the IF definitely worked out more efficient on the server and returned the desired results.
Many thanks to all who commented.
The code I used is:
select drname,
sum((month(loaddate) = 1 ) * drvalue) as 'Jan',
sum((month(loaddate) = 2 ) * drvalue) as 'Feb',
sum((month(loaddate) = 3 ) * drvalue) as 'March',
sum((month(loaddate) = 4 ) * drvalue) as 'April',
sum((month(loaddate) = 5 ) * drvalue) as 'May',
sum((month(loaddate) = 6 ) * drvalue) as 'June'
from tblloadschedule
where cancelloadflag = 'N'
group by drname

Related

sql How to hide row if entire row value is 0

My Query :
SELECT
(ref_intake.intakeno) AS intake,
SUM(CASE WHEN(student.intakeid AND student.status = '3' AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as active,
SUM(CASE WHEN(student.intakeid AND student.status = '5' AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as deffered,
SUM(CASE WHEN(student.intakeid AND student.status = '16' AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as inactive,
SUM(CASE WHEN(student.intakeid AND student.status = '9' AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as missing,
SUM(CASE WHEN(student.intakeid AND student.status = '6' AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as widthdrawn,
SUM(CASE WHEN(student.intakeid AND student.status IN (18,7,36) AND (student.courseid=3 OR student.courseid=17)) THEN 1 else 0 END) as dis_ter_dereg
FROM student
LEFT JOIN ref_intake ON student.intakeid = ref_intake.intakeid
GROUP BY student.intakeid ORDER BY ref_intake.intakeno ASC
The the image is my result:
I do suspect that your query can be simplified as follows:
SELECT
s.intakeid AS intake,
SUM(CASE WHEN s.status = 3 THEN 1 ELSE 0 END) as active,
SUM(CASE WHEN s.status = 5 THEN 1 ELSE 0 END) as deffered,
SUM(CASE WHEN s.status = 16 THEN 1 ELSE 0 END) as inactive,
SUM(CASE WHEN s.status = 9 THEN 1 ELSE 0 END) as missing,
SUM(CASE WHEN s.status = 6 THEN 1 ELSE 0 END) as widthdrawn,
SUM(CASE WHEN s.status IN (18, 7, 36) THEN 1 ELSE 0 END) as dis_ter_dereg
FROM student s
INNER JOIN ref_intake ri ON s.intakeid = ri.intakeid
WHERE
s.intakeid
AND s.status IN (3, 5, 16, 9, 6, 18, 7, 36)
AND s.courseid IN (3, 17)
GROUP BY s.intakeid
ORDER BY ri.intakeno ASC
That is:
most conditions can be moved to the WHERE clause - this should actually remove rows where no condition matches
it seems like you actually want an INNER JOIN rather than a LEFT JOIN - but you can revert that change if needed
table aliases make the query easier to read and write
ORed conditions can be simplified to use IN

Adapting two queries

Hello again community.
I recently received help with the solution to a problem that consisted of List grouped data by month including months in which there are no results
Now I have the same scenario but with the difference that there is a condition to evaluate. I need to adapt this query
select
date_format(a.date_created, '%b') month,
month(a.date_created) pivot,
sum(case when a.state = 'created' then 1 else 0 end) created,
sum(case when a.state = 'notified' then 1 else 0 end) notified,
sum(case when a.state = 'confirmed' then 1 else 0 end) confirmed,
sum(case when a.state = 'approved' then 1 else 0 end) approved,
sum(case when a.state = 'authorized' then 1 else 0 end) authorized,
sum(case when a.state = 'attended' then 1 else 0 end) attended,
sum(case when a.state = 'canceled' then 1 else 0 end) canceled,
count(a.id) as total
from
activities a
inner join
employees e on a.employee_id = e.id
where
e.id = 8
group by 1, 2 order by pivot desc;
To this query
select
s.name month,
s.m pivot,
sum(case when a.state = 'created' then 1 else 0 end) created,
sum(case when a.state = 'notified' then 1 else 0 end) notified,
sum(case when a.state = 'confirmed' then 1 else 0 end) confirmed,
sum(case when a.state = 'approved' then 1 else 0 end) approved,
sum(case when a.state = 'authorized' then 1 else 0 end) authorized,
sum(case when a.state = 'attended' then 1 else 0 end) attended,
sum(case when a.state = 'canceled' then 1 else 0 end) canceled,
count(a.id) as total
from (
SELECT 1 m, 'Jan' AS name
UNION SELECT 2, 'Feb'
UNION SELECT 3, 'Mar'
UNION SELECT 4, 'Apr'
UNION SELECT 5, 'May'
UNION SELECT 6, 'Jun'
UNION SELECT 7, 'Jul'
UNION SELECT 8, 'Aug'
UNION SELECT 9, 'Sep'
UNION SELECT 10, 'Oct'
UNION SELECT 11, 'Nov'
UNION SELECT 12, 'Dec'
) s
LEFT JOIN activities a
ON s.m = month(date_created)
group by 1, 2 order by pivot desc;
I do not know how in the context of the solution that worked in the previous question add the condition
I have tested the following but the months in which there are no results are not listed
select
s.name month,
s.m pivot,
sum(case when a.state = 'created' then 1 else 0 end) created,
sum(case when a.state = 'notified' then 1 else 0 end) notified,
sum(case when a.state = 'confirmed' then 1 else 0 end) confirmed,
sum(case when a.state = 'approved' then 1 else 0 end) approved,
sum(case when a.state = 'authorized' then 1 else 0 end) authorized,
sum(case when a.state = 'attended' then 1 else 0 end) attended,
sum(case when a.state = 'canceled' then 1 else 0 end) canceled,
count(a.id) as total
from (
SELECT 1 m, 'Jan' AS name
UNION SELECT 2, 'Feb'
UNION SELECT 3, 'Mar'
UNION SELECT 4, 'Apr'
UNION SELECT 5, 'May'
UNION SELECT 6, 'Jun'
UNION SELECT 7, 'Jul'
UNION SELECT 8, 'Aug'
UNION SELECT 9, 'Sep'
UNION SELECT 10, 'Oct'
UNION SELECT 11, 'Nov'
UNION SELECT 12, 'Dec'
) s
LEFT JOIN activities a
ON s.m = month(date_created)
inner join employees e on a.employee_id = e.id
group by 1, 2 order by pivot desc;
I share the following sqlfiddle that includes the relationship between employee and activity
I am expecting for the user with id 2 the results should be as follows
Again, thank you very much.
You just had the joins muddled. For the join between activities and employees to be considered as INNER join it has to be enclosed in brackets. Let's know whether it works!
Here is the solution
select
s.name month,
s.m pivot,
sum(case when a.state = 'created' then 1 else 0 end) created,
sum(case when a.state = 'notified' then 1 else 0 end) notified,
sum(case when a.state = 'confirmed' then 1 else 0 end) confirmed,
sum(case when a.state = 'approved' then 1 else 0 end) approved,
sum(case when a.state = 'authorized' then 1 else 0 end) authorized,
sum(case when a.state = 'attended' then 1 else 0 end) attended,
sum(case when a.state = 'canceled' then 1 else 0 end) canceled,
count(a.id) as total
from (
SELECT 1 m, 'Jan' AS name
UNION SELECT 2, 'Feb'
UNION SELECT 3, 'Mar'
UNION SELECT 4, 'Apr'
UNION SELECT 5, 'May'
UNION SELECT 6, 'Jun'
UNION SELECT 7, 'Jul'
UNION SELECT 8, 'Aug'
UNION SELECT 9, 'Sep'
UNION SELECT 10, 'Oct'
UNION SELECT 11, 'Nov'
UNION SELECT 12, 'Dec'
) s
LEFT JOIN ( activities a INNER JOIN employees e
ON a.employee_id = e.id AND e.id = 2)
ON (s.m = month(a.date_created))
group by 1, 2 order by pivot desc;
I think this version does what you want:
select s.name as month, s.m as pivot,
sum(case when a.state = 'created' then 1 else 0 end) created,
sum(case when a.state = 'notified' then 1 else 0 end) notified,
sum(case when a.state = 'confirmed' then 1 else 0 end) confirmed,
sum(case when a.state = 'approved' then 1 else 0 end) approved,
sum(case when a.state = 'authorized' then 1 else 0 end) authorized,
sum(case when a.state = 'attended' then 1 else 0 end) attended,
sum(case when a.state = 'canceled' then 1 else 0 end) canceled,
count(a.id) as total
from (SELECT 1 m, 'Jan' AS name UNION ALL
SELECT 2, 'Feb' UNION ALL
SELECT 3, 'Mar' UNION ALL
SELECT 4, 'Apr' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'Jun' UNION ALL
SELECT 7, 'Jul' UNION ALL
SELECT 8, 'Aug' UNION ALL
SELECT 9, 'Sep' UNION ALL
SELECT 10, 'Oct' UNION ALL
SELECT 11, 'Nov' UNION ALL
SELECT 12, 'Dec'
) s LEFT JOIN activities a
ON s.m = month(date_created) left join
employees e
on a.employee_id = e.id AND e.id = 2
group by 1, 2
order by pivot desc;
Here is the SQL Fiddle.
The major change is moving the condition on e.id to the ON clause and changing the second join to a LEFT JOIN. In addition, I changed the UNION to UNION ALL, to eliminate the overhead of removing duplicates.

MySql union Sum(Case())

How can I do a "union" in order to get only distinct values for "ACTIVITY" field, but with the variables started by "OUTPUT_" from "OUTPUT_TAB" appearing in the header. (Like "INPUT_" variables from "INPUT_TAB") .
It's possible ? I can not do it.
Check my Query PIC_QUERY:
SELECT
ACTIVIDADE,
SUM(CASE WHEN DATA_VAL_REGISTO = '2017-06-25' THEN 1 ELSE 0 END) INPUT_ACT_DATE_VOL,
SUM(CASE WHEN DATA_VAL_REGISTO = '2017-06-24' THEN 1 ELSE 0 END) PREV_DATE_VOL,
SUM(CASE WHEN WEEK(DATA_VAL_REGISTO,7) = '25' AND YEAR(DATA_VAL_REGISTO) = '2017' THEN 1 ELSE 0 END) INPUT_ACT_WEEK_VOL,
SUM(CASE WHEN WEEK(DATA_VAL_REGISTO,7) = '24' AND YEAR(DATA_VAL_REGISTO) = '2017' THEN 1 ELSE 0 END) INPUT_PREV_WEEK_VOL,
SUM(CASE WHEN MONTH(DATA_VAL_REGISTO) = '6' AND YEAR(DATA_VAL_REGISTO) = '2017' THEN 1 ELSE 0 END) INPUT_ACT_MONTH_VOL,
SUM(CASE WHEN MONTH(DATA_VAL_REGISTO) = '5' AND YEAR(DATA_VAL_REGISTO) = '2017' THEN 1 ELSE 0 END) INPUT_PREV_MONTH_VOL
FROM INPUT_TAB
GROUP BY ACTIVIDADE
UNION
SELECT
ACTIVIDADE,
SUM(CASE WHEN DATA_FIM_REP = '2017-06-25' THEN 1 ELSE 0 END) OUTPUT_ACT_DATE_VOL,
SUM(CASE WHEN DATA_FIM_REP = '2017-06-24' THEN 1 ELSE 0 END) OUTPUT_PREV_DATE_VOL,
SUM(CASE WHEN WEEK(DATA_FIM_REP,7) = '25' AND YEAR(DATA_FIM_REP) = '2017' THEN 1 ELSE 0 END) OUTPUT_ACT_WEEK_VOL,
SUM(CASE WHEN WEEK(DATA_FIM_REP,7) = '24' AND YEAR(DATA_FIM_REP) = '2017' THEN 1 ELSE 0 END) OUTPUT_PREV_WEEK_VOL,
SUM(CASE WHEN MONTH(DATA_FIM_REP) = '6' AND YEAR(DATA_FIM_REP) = '2017' THEN 1 ELSE 0 END) OUTPUT_ACT_MONTH_VOL,
SUM(CASE WHEN MONTH(DATA_FIM_REP) = '5' AND YEAR(DATA_FIM_REP) = '2017' THEN 1 ELSE 0 END) OUTPUT_PREV_MONTH_VOL
FROM OUTPUT_TAB
GROUP BY ACTIVIDADE
RESULT: PIC_RESULT
You don't want a union of two query results, but a join:
SELECT
actividade,
i.input_act_date_vol, i.input_prev_date_vol, i.input_act_week_vol,
i.input_prev_week_vol, i.input_act_month_vol, i.input_prev_month_vol,
o.output_act_date_vol, o.output_prev_date_vol, o.output_act_week_vol,
o.output_prev_week_vol, o.output_act_month_vol, o.output_prev_month_vol
FROM
(
SELECT
actividade,
SUM(data_val_registo = '2017-06-25') AS input_act_date_vol,
SUM(data_val_registo = '2017-06-24') AS input_prev_date_vol,
SUM(WEEK(data_val_registo, 7) = 25 AND YEAR(data_val_registo) = 2017) AS input_act_week_vol,
SUM(WEEK(data_val_registo, 7) = 24 AND YEAR(data_val_registo) = 2017) AS input_prev_week_vol,
SUM(MONTH(data_val_registo) = 6 AND YEAR(data_val_registo) = 2017) AS input_act_month_vol,
SUM(MONTH(data_val_registo) = 5 AND YEAR(data_val_registo) = 2017) AS input_prev_month_vol
FROM input_tab
GROUP BY actividade
) i
JOIN
(
SELECT
actividade,
SUM(data_fim_rep = '2017-06-25') AS output_act_date_vol,
SUM(data_fim_rep = '2017-06-24') AS output_prev_date_vol,
SUM(WEEK(data_fim_rep, 7) = 25 AND YEAR(data_fim_rep) = 2017) AS output_act_week_vol,
SUM(WEEK(data_fim_rep, 7) = 24 AND YEAR(data_fim_rep) = 2017) AS output_prev_week_vol,
SUM(MONTH(data_fim_rep) = 6 AND YEAR(data_fim_rep) = 2017) AS output_act_month_vol,
SUM(MONTH(data_fim_rep) = 5 AND YEAR(data_fim_rep) = 2017) ASoutput_prev_month_vol
FROM OUTPUT_TAB
GROUP BY actividade
) o USING (actividade);
In case there can be input without output or vice versa, you'll have to use an outer join instead. In case there can even be both, input without output and output without input, you'll have to look up how to emulate a full outer join in MySQL.
I've removed CASE WHEN .. THEN 1 ELSE 0 END, because a boolean expression results in true or false which equal to 1 and 0 in MySQL.
BTW: As this is all about 2017, you can get your queries simpler and faster by using WHERE YEAR(data_val_registo) and WHERE YEAR(data_fim_rep) = 2017 and removing the condition from the sum expressions.

MySQL get all users, whether or not they have any hours?

Trying to get all users, whether or not they have any hours? My LEFT OUTER JOIN still not working..
SELECT tblleaverequest.lqUser,
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 1 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jan',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 2 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Feb',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 3 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Mar',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 4 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Apr',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 5 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'May',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 6 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jun',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 7 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jul',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 8 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Aug',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 9 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Sep',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 10 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Oct',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 11 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Nov',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 12 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Dec',
SUM(tblleaverequest.lqHoursPL) AS PaidLeaveTotal
FROM tblusers LEFT OUTER JOIN tblleaverequest ON tblleaverequest.lqUser = tblusers.username
WHERE (tblusers.clr_accrual = '1') AND (YEAR(tblleaverequest.lqStartDate) = YEAR(CURDATE()))
GROUP BY tblusers.username
Here are my results, but I need to have the rest of the users w/o hours too.
Not sure about you db schema, but seem you just can move one condition from WHERE to ON clause
SELECT tblusers.username,
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 1 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jan',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 2 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Feb',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 3 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Mar',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 4 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Apr',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 5 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'May',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 6 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jun',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 7 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Jul',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 8 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Aug',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 9 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Sep',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 10 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Oct',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 11 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Nov',
SUM(CASE WHEN DATE_FORMAT(tblleaverequest.lqStartDate, '%m') = 12 THEN (tblleaverequest.lqHoursPL) ELSE 0 END) AS 'Dec',
SUM(tblleaverequest.lqHoursPL) AS PaidLeaveTotal
FROM tblusers
LEFT OUTER JOIN tblleaverequest
ON tblleaverequest.lqUser = tblusers.username
AND (YEAR(tblleaverequest.lqStartDate) = YEAR(CURDATE()))
WHERE (tblusers.clr_accrual = '1')
GROUP BY tblusers.username
WHERE ... (YEAR(tblleaverequest.lqStartDate) = YEAR(CURDATE()))
If there are no matching in records tblLeaveRequest, the date will be null. Since a null cannot equal anything, those records will be dropped. So you are essentially converting the OUTER JOIN to an INNER JOIN. Move that comparison to the JOIN statement to preserve the OUTER JOIN.
Update:
Be sure to grab the username from tblusers, since the tblleaverequest.lqUser value may be null due to the OUTER JOIN.
SELECT tblusers.username
, SUM(CASE ......)) AS Jan
, ....

Calculate date difference in sql for specific year

I have two dates, say start_date is 20141215 and end_date = 20150115. I would like to use SQL DATEDIFF to only count the dates within the year 2015 which I will specify in the query. Here is the current SQL I have written:
SELECT COUNT(leave_id),
sum(case when leave_status = 1 then 1 else 0 end) pending,
sum(case when leave_status = 2 then 1 else 0 end) declined,
sum(case when leave_status = 3 then 1 else 0 end) approved,
sum(case when leave_status = 4 then 1 else 0 end) rostered,
SUM(DATEDIFF(end_date, start_date)+1) as datetotals
FROM employee_leave WHERE
((YEAR(start_date) = :year) OR (YEAR(end_date) = :year))
AND employee_id = :emp_id
Thanks
You need to fix datediff() to only consider dates during the year. I think this does what you want:
SELECT COUNT(leave_id),
sum(case when leave_status = 1 then 1 else 0 end) pending,
sum(case when leave_status = 2 then 1 else 0 end) declined,
sum(case when leave_status = 3 then 1 else 0 end) approved,
sum(case when leave_status = 4 then 1 else 0 end) rostered,
SUM(DATEDIFF(least(end_date, date(concat_ws('-', :year, 12, 31))),
greatest(start_date, date(concat_ws('-', :year, 1, 1)))
) + 1) as datetotals
FROM employee_leave
WHERE ((YEAR(start_date) = :year) OR (YEAR(end_date) = :year)) AND
employee_id = :emp_id
Make it a AND condition rather like
WHERE
((YEAR(start_date) = :year) AND (YEAR(end_date) = :year))