GROUP BY on table returning incorrect counts in MySQL with LEFT JOIN - mysql

I am trying to return multiple counts and averages from multiple tables sorting by gender and am getting incorrect data. I understand that the following is incorrect, but I am unsure of how to fix it. (Edit: Problem with group by gender. See below.)
Here is the query:
SELECT c.gender AS 'Gender',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
(SELECT COUNT(DISTINCT CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) ) AS 'Open Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Avg Open',
(SELECT COUNT(DISTINCT CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) ) AS 'Click Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Avg Click',
COUNT(DISTINCT ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM ((mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id)
LEFT JOIN mailing_recipient_click mrc ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON c.cons_id = ca.cons_id)
WHERE m.mailing_id = 1
AND gender IS NOT NULL
GROUP BY c.gender;
Here is the table which would be correct if the totals in the fields were correct:
GENDER Mailing Recipient Open Total Avg Open Click Total Avg Click Donations Avg Amt
F 105 2 0.5000 2 0.5000 105 22.5000
M 98 2 0.5000 2 0.5000 98 18.8780
EDIT: Here is an example of what I am hoping to achieve. I am certain that the above values are being repeated. The below values are just examples of what I am expecting:
GENDER Mailing Recipient Open Total Avg Open Click Total Avg Click Donations Avg Amt
F 105 8 0.0761 4 0.0380 2 22.5000
M 98 2 0.0204 1 0.0102 1 18.8000
Edit:
After playing around a bit, I thought that I had discovered that the joining the cons table was what is giving me problematic returns, but the problem is with GROUP BY when using gender. To illustrate, this query (which is grouped by mailing name instead of gender) works beautifully.
select m.mailing_name AS 'mailing',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
SUM(CASE
when mrc.mailing_recipient_click_type_id = 2 THEN 1
END)
AS 'Open Total',
AVG(CASE
WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1
ELSE 0
END) AS 'Avg Open',
SUM(CASE
WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1
END)
AS 'Click Total',
AVG(CASE
WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1
ELSE 0
END) AS 'Avg Click',
COUNT(ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM
mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id
LEFT JOIN mailing_recipient_click mrc
ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON mr.cons_id = c.cons_id
WHERE m.mailing_id = 1
GROUP BY m.mailing_name;
The statement is identical with the exception of the first and last lines.

Try this:
I'm not sure what you mean by Avg Open and Avg Click.
SELECT c.gender AS 'Gender',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
SUM(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Open Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Avg Open',
SUM(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Click Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Avg Click',
COUNT(DISTINCT ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id
LEFT JOIN mailing_recipient_click mrc ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON c.cons_id = ca.cons_id
WHERE m.mailing_id = 1
AND gender IS NOT NULL
GROUP BY c.gender;
I also think that mrc.mailing_recipient_click_type_id = 2 means open and mrc.mailing_recipient_click_type_id = 1 mean click seems strange to me. I would expect this data to be exclusive and stored in two different fields.

Related

Convert Total Sum Into Percentage

I want to convert a sum result into percentage. When added it will result 100% in total. I already group it by remarks and already got the total from my query. But its still in number.
This is my query
SELECT
CASE
WHEN A.district = B.district THEN 'Delivered from store in same district'
WHEN A.city = B.city THEN 'Delivered from store in same city'
WHEN A.province = B.province THEN 'Delivered from store in same province'
ELSE 'Not delivered from nearest store'
END AS 'REMARK',
SUM(CASE
WHEN YEAR(T1.create_time) = '2019' AND MONTH(T1.create_time) = '01' THEN 1
ELSE 0
END) AS 'Jan-19',
SUM(CASE
WHEN YEAR(T1.create_time) = '2019' AND MONTH(T1.create_time) = '02' THEN 1
ELSE 0
END) AS 'Feb-19',
SUM(CASE
WHEN YEAR(T1.create_time) = '2019' AND MONTH(T1.create_time) = '03' THEN 1
ELSE 0
END) AS 'Mar-19',
SUM(CASE
WHEN YEAR(T1.create_time) = '2019' AND MONTH(T1.create_time) = '04' THEN 1
ELSE 0
END) AS 'Apr-19'
FROM
au_store_add A
INNER JOIN
(SELECT
A.id,
A.code,
A.create_time,
A.plat_create_time,
A.appoint_stcode,
A.status
FROM deli_order A
WHERE A.appoint_stcode IS NOT NULL
UNION
SELECT
B.id,
B.code,
B.create_time,
B.plat_create_time,
B.destination_code,
B.status
FROM deli_order B
WHERE B.destination_code IS NOT NULL) T1 ON T1.appoint_stcode = A.store_code
INNER JOIN
deli_order_delivery B ON B.order_id = T1.id
WHERE
YEAR(T1.plat_create_time)='2019' and T1.status = 6 and (month(T1.plat_create_time) in (1,2,3,4))
GROUP BY
CASE
WHEN A.district = B.district THEN 'Delivered from store in same district'
WHEN A.city = B.city THEN 'Delivered from store in same city'
WHEN A.province = B.province THEN 'Delivered from store in same province'
ELSE 'Not delivered from nearest store'
END
And the result is like this
REMARK | Jan-19| Feb-19| Mar-19| Apr-19|
-----------------------------------------------------------------------
Delivered from store in same city 252 198 308 283
Delivered from store in same district 114 110 163 138
Delivered from store in same province 1135 976 1387 1208
Not delivered from nearest store 3046 2518 3189 3123
I need to generate something like this for each month(without the 'Grand Total')
REMARK | Jan-19|
-----------------------------------------------
Delivered from store in same city 5.5%
Delivered from store in same district 2.5%
Delivered from store in same province 25%
Not delivered from nearest store 67%
Grand Total 4547 (100%)
What should i add to my query?
Given that you are using MySQL 8+, then COUNT() as an analytic function should be available to use. It comes in handy here:
SELECT
CASE
WHEN A.district = B.district THEN 'Delivered from store in same district'
WHEN A.city = B.city THEN 'Delivered from store in same city'
WHEN A.province = B.province THEN 'Delivered from store in same province'
ELSE 'Not delivered from nearest store'
END AS REMARK,
100.0 * COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-01' THEN 1 END)
/ COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-01'
THEN 1 END) OVER () `Jan-19`,
100.0 * COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-02' THEN 1 END)
/ COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-02'
THEN 1 END) OVER () `Feb-19`,
100.0 * COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-03' THEN 1 END)
/ COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-03'
THEN 1 END) OVER () `Mar-19`,
100.0 * COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-04' THEN 1 END)
/ COUNT(CASE WHEN DATE_FORMAT(create_time, '%Y-%m') = '2019-04'
THEN 1 END) OVER () `Apr-19`
FROM
au_store_add A
...
I used DATE_FORMAT above to make the check on the year and month a bit less verbose. I also used COUNT in place of SUM, which lets us use a slightly shorter conditional expression.

SQL query time difference when adding an inner join and group by gives wrong calculations

Am trying to come up with an sql query to calculate, the time difference from a start time and an end time, then sum up the duration for each school.
I have the following table :
-Class /*Contains all the classes tied to a school using school_id */
-School /*contains all the schools in tied to a hub using hub_id */
-Hub /*contains all the hubs details (one hub can have many schools in it) */
-student /*contains student profile, which is tied to a class using class_id */
-session_details /contains the session details which include the session start time, end time, session_id,/
-student_attendance_register /* used to mark the register for all the students in a class for a particular session using session_id
and student_id as in_attendance=0 or in_attendance =1 /*
I have a mini query which works perfect, the query calculates the duration of the session and finds the total duration for all the classes in a school.
select
c.class_name,c.school_id,d.school_name,e.session_date,e.time_finish,e.time_start,
CAST(sum(TIMEDIFF(e.time_finish, e.time_start)) as TIME) as duration
From session_details as e
Inner join class as c
on c.id = e.class_id
Inner join school as d
on c.school_id = d.id
group by c.school_id;
My problem pops up when i add inner joins to get the student profile and their attendance. See below my query
select
a.session_details_id,c.class_name,c.school_id,d.school_name,
e.class_id,e.session_date,e.time_finish,e.time_start,
SUM((TIME_TO_SEC(e.time_finish) - TIME_TO_SEC(e.time_start))/60) as session_duration,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN b.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN b.gender = 1 then 1 END) as boys_total
from session_details as e
inner join class as c
on c.id = e.class_id
inner join school as d
on c.school_id = d.id
inner join attendance_student as a
on e.id = a.session_details_id
inner join student as b
on a.student_id = b.id
group by c.school_id;
Image 1 shows the results set without with group for all session that were done for each class in a school. This returns correct time duration.
Image 2 shows the result set with group for all session that we done for each class in a school.
When running query 2, whereby which is an extension of query one for adding the student profile and the total no of students who were in attendance.
When running query 2,without grouping by shool_id i get the following results
Note
-I have tried to change the time to seconds then do the division then convert to minutes which return the wrong total.
sum((TIME_TO_SEC(e.time_finish) - TIME_TO_SEC(e.time_start)))/60 as duration
-I have also tried to do a sum for the time finish in second, subtract the finish and start time then divide the total
-Am also in doubt of how am doing my inner joins, and maybe the problem lies in there, since once i introduce the inner joins to students i get the errors. Other totals are working ok except for my finish and start time which are time data type on the database.
Here is a link to the related tables.
Kindly assit on how best to go about doing a correct calculation for the duration once i inner join and group the tables. :)
http://sqlfiddle.com/#!9/36bb8/2
If I understood all the details, the problem is in the group by. You must group by every field with no aggregation function (like SUM or COUNT). Using your second SQL query you change the group by like this :
select
a.session_details_id,c.class_name,c.school_id,d.school_name,
e.class_id,e.session_date,e.time_finish,e.time_start,
SUM((TIME_TO_SEC(e.time_finish) - TIME_TO_SEC(e.time_start))/60) as session_duration,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN b.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN b.gender = 1 then 1 END) as boys_total
from session_details as e
inner join class as c
on c.id = e.class_id
inner join school as d
on c.school_id = d.id
inner join attendance_student as a
on e.id = a.session_details_id
inner join student as b
on a.student_id = b.id
group by a.session_details_id,c.class_name,c.school_id,d.school_name,
e.class_id,e.session_date,e.time_finish,e.time_start
But, then, the SUM in the session_duration calculation, add the total duration for each student, so you need to make calculation of session_duration without aggregation function:
select
a.session_details_id,c.class_name,c.school_id,d.school_name,
e.class_id,e.session_date,e.time_finish,e.time_start,
(TIME_TO_SEC(e.time_finish) - TIME_TO_SEC(e.time_start))/60 as session_duration,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and b.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and b.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN b.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN b.gender = 1 then 1 END) as boys_total
from session_details as e
inner join class as c
on c.id = e.class_id
inner join school as d
on c.school_id = d.id
inner join attendance_student as a
on e.id = a.session_details_id
inner join student as b
on a.student_id = b.id
group by a.session_details_id,c.class_name,c.school_id,d.school_name,
e.class_id,e.session_date,e.time_finish,e.time_start
If you run this query on SQLFiddle you provide, your results are:
-- Edited --
After your comments I'll try again ;)
If you strip off class_id, session_date, time_start, time_finish to only get totals by school, this query will do the work:
select
c.school_id, sc.school_name,
sum((TIME_TO_SEC(sd.time_finish) - TIME_TO_SEC(sd.time_start))/60) as session_duration,
sum(stc.boys_present) boys_present, sum(stc.girls_present) girls_present,
sum(stc.boys_absent) boys_absent, sum(stc.girls_absent) girls_absent,
sum(stc.boys_total) boys_total, sum(stc.girls_total) girls_total
from session_details sd
inner join (
select a.session_details_id,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN s.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN s.gender = 1 then 1 END) as boys_total
from attendance_student a
inner join student s
on a.student_id = s.id
group by a.session_details_id
) stc
on sd.id = stc.session_details_id
inner join class c
on sd.class_id = c.id
inner join school sc
on c.school_id = sc.id
group by c.school_id, sc.school_name
Here I use a different approach making a subquery (maybe you prefer save as a view) to calculate student assistance totals.
First I count the students for each session using only two tables, attendance_student and student. Results are grouped by th ID os the session, so I have students by session. This query can be saved as a view for readability.
select a.session_details_id,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN s.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN s.gender = 1 then 1 END) as boys_total
from attendance_student a
inner join student s
on a.student_id = s.id
group by a.session_details_id
) stc
After that I join this results with session_details to calculate session_duration for each session. Our resultset now has a session_details_id, session_duration and the count of students (one row for each session).
select
sd.id as session_id,
(TIME_TO_SEC(sd.time_finish) - TIME_TO_SEC(sd.time_start))/60 as session_duration,
sum(stc.boys_present) boys_present, sum(stc.girls_present) girls_present,
sum(stc.boys_absent) boys_absent, sum(stc.girls_absent) girls_absent,
sum(stc.boys_total) boys_total, sum(stc.girls_total) girls_total
from session_details sd
inner join (
select a.session_details_id,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 1 then 1 END) as boys_present,
COUNT(CASE WHEN a.in_attendance = 1 and s.gender = 2 then 1 END) as girls_present,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 1 then 1 END) as boys_absent,
COUNT(CASE WHEN a.in_attendance = 0 and s.gender = 2 then 1 END) as girls_absent,
COUNT(CASE WHEN s.gender = 2 then 1 END) as girls_total,
COUNT(CASE WHEN s.gender = 1 then 1 END) as boys_total
from attendance_student a
inner join student s
on a.student_id = s.id
group by a.session_details_id
) stc
on sd.id = stc.session_details_id
We want to sum results by school so we need add to more tables, class and school. We don't really need class table to show any data but an intermediate table to get school data.

How to use user variable as counter with inner join queries that contains GROUP BY statement?

I have 2 tables odds and matches :
matches : has match_id and match_date
odds : has id, timestamp, result, odd_value, user_id, match_id
I had a query that get the following information from those tables for each user:
winnings : the winning bets for each user. (when odds.result = 1)
loses : the lost bets for each user.(when odds.result != 1)
points : the points of each user.(the sum of the odds.odd_value) for each user.
bonus : for each continuous 5 winnings i want to add extra bonus to this variable. (for each user)
How to calculate bonus?
I tried to use this query and I faced a problem : (you can check it here SQL Fiddle)
the calculated bonus are not right for all the users :
first user:(winnings:13, bonus=2).
second user:(winnings:8, bonus=2)bonus here should be 1.
third user:(winnings:14, bonus=3)bonus here should be 2.
why does the query not calculate the bonus correctly?
select d.user_id,
sum(case when d.result = 1 then 1 else 0 end) as winnings,
sum(case when d.result = 2 then 1 else 0 end) as loses,
sum(case when d.result = 1 then d.odd_value else 0 end) as points,
f.bonus
FROM odds d
INNER JOIN
(
SELECT
user_id,SUM(CASE WHEN F1=5 THEN 1 ELSE 0 END) AS bonus
FROM
(
SELECT
user_id,
CASE WHEN result=1 and #counter<5 THEN #counter:=#counter+1 WHEN result=1 and #counter=5 THEN #counter:=1 ELSE #counter:=0 END AS F1
FROM odds o
cross join (SELECT #counter:=0) AS t
INNER JOIN matches mc on mc.match_id = o.match_id
WHERE MONTH(STR_TO_DATE(mc.match_date, '%Y-%m-%d')) = 2 AND
YEAR(STR_TO_DATE(mc.match_date, '%Y-%m-%d')) = 2015 AND
(YEAR(o.timestamp)=2015 AND MONTH(o.timestamp) = 02)
) Temp
group by user_id
)as f on f.user_id = d.user_id
group by d.user_id
I am not sure how your result related to matches table,
you can add back WHERE / INNER JOIN clause if you need.
Here is link to fiddle
and the last iteration according to your comments:
And here is a query:
SET #user:=0;
select d.user_id,
sum(case when d.result = 1 then 1 else 0 end) as winnings,
sum(case when d.result = 2 then 1 else 0 end) as loses,
sum(case when d.result = 1 then d.odd_value else 0 end) as points,
f.bonus
FROM odds d
INNER JOIN
(
SELECT
user_id,SUM(bonus) AS bonus
FROM
(
SELECT
user_id,
CASE WHEN result=1 and #counter<5 AND #user=user_id THEN #counter:=#counter+1
WHEN result=1 and #counter=5 AND #user=user_id THEN #counter:=1
WHEN result=1 and #user<>user_id THEN #counter:=1
ELSE
#counter:=0
END AS F1,
#user:=user_id,
CASE WHEN #counter=5 THEN 1 ELSE 0 END AS bonus
FROM odds o
ORDER BY user_id , match_id
) Temp
group by user_id
)as f on f.user_id = d.user_id
group by d.user_id

mysql sort group by total and name not working

I have Php program that outputs names with the corresponding events attended and the number of times each event was attended over a period of time. As an example of the output
Name | Run | Swim | Bike | Total
John 3 2 5 10
MySQL query look something like this:
$sql = 'SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP;';
This works well, however, if I want to sort my data by "total" in descending order I get no output if I replace the last GROUP BY line with the following:
GROUP BY total DESC, Leader WITH ROLLUP;';
so that I get a listing with names who have the highest totals to the lowest, and people with the same totals get listed in alphabetical order. What am I doing wrong?
As mentioned in the comments, the ORDER BY and ROLLUP can not be used together. It states this here (http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html) about half way down the page. To get around this, you'll have to do the ORDER BY in another query where your original query acts as the subquery:
SELECT *
FROM
(
SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP
) as rolldup
ORDER BY Total DESC
ORIGINAL (WRONG) ANSWER:
You do not put Sorts in a GROUP BY clause. You put them in your ORDER BY clause:
$sql = 'SELECT
e.name as Leader,
SUM(CASE WHEN c.catid = 26 THEN 1 ELSE null END) as "Swim",
SUM(CASE WHEN c.catid = 25 THEN 1 ELSE null END) as "Bike",
SUM(CASE WHEN c.catid = 24 THEN 1 ELSE null END) as "Run",
COUNT("Swim"+"Bike"+"Run") as total
FROM
events as e
LEFT JOIN event_categories as c ON c.uid = e.uid
WHERE
(DATE(e.event_start) BETWEEN "'.$from_date.'" and "'.$to_date.'")
GROUP BY Leader WITH ROLLUP
ORDER BY total DESC;';
You don't want to GROUP BY Total you just want to ORDER BY total.
So the two last lines of your query should be
GROUP BY Leader WITH ROLLUP
ORDER BY total DESC

how to select and group mysql data based on the following table

how can I achieve the desired result in mysql if my table looks like this.
result|year
1 |2011
2 |2011
1 |2011
0 |2011
1 |2012
2 |2012
1 = Won, 2 = lost, 0 = draw
Every year can have multiple values like this. Not sure how I can get the desired result like below.
year won lost draw totalPlayed
2011 2 1 1 3
2012 1 1 0 2
I have tried the following query but does not get the desired result
select year,
league_types.league_name,
sum(if(result = 1,1,0)) as won,
sum(if(result = 0,1,0)) as draw,
sum(if(result = 4,1,0)) as noResult,
sum(if(result = 2,1,0)) as lost,
sum(if(result = 3,1,0)) as tied,
sum(if(result > 0 and result < 4,1,0)) as played
from match_score_card
inner join fixtures on match_score_card.match_id = fixtures.match_id
inner join league_types on fixtures.league_id = league_types.league_id
where
team_id = 1 group by year order by year desc
Here is the SQL Fiddle that demonstrates the following query:
SELECT m.year,
SUM(CASE WHEN m.result = 1 THEN 1 ELSE 0 END) AS 'Won',
SUM(CASE WHEN m.result = 2 THEN 1 ELSE 0 END) AS 'Lost',
SUM(CASE WHEN m.result = 0 THEN 1 ELSE 0 END) AS 'Draw',
COUNT(*) AS 'TotalPlayed'
FROM MyTable AS m
GROUP BY m.year
I'm not familiar with that IF function in mySQL, but this standard SQL should work:
select year
, league_types.league_name
, sum(CASE WHEN result = 1 THEN 1 ELSE 0 END) as won
, sum(CASE WHEN result = 2 THEN 1 ELSE 0 END) as lost
, sum(CASE WHEN result = 3 THEN 1 ELSE 0 END) as draw
, sum(CASE WHEN result = 4 THEN 1 ELSE 0 END) as noResult
, sum(CASE WHEN result = 1
or result = 2 THEN 1 ELSE 0 END) as played
from match_score_card
inner join fixtures
on match_score_card.match_id = fixtures.match_id
inner join league_types
on fixtures.league_id = league_types.league_id
where team_id = 1
group by year, league_types.league_name
order by year desc, league_types.league_name
I'm guessing that you only want to count wins and losses as "played".