SQL Group Function - mysql

I was trying to get count of three columns by using SUM(), when I execute the query, it says '#1111 - Invalid use of group function'. I tried correcting the group functions, even though it shows the error.
I need the perfect count of columns 2,3,4
SELECT c.name,
SUM(CASE WHEN COUNT(distinct cmc.id) = COUNT(distinct ccc.id) THEN 1 ELSE 0 END) AS "COND1",
SUM(CASE WHEN COUNT(distinct cmc.id) > 0 AND COUNT(distinct cmc.id) != COUNT(distinct ccc.id) THEN 2 ELSE 0 END) AS "COND2",
SUM(CASE WHEN COUNT(distinct cmc.id) = 0 THEN 3 ELSE 0 END) AS "COND3"
FROM
lesson_modules_completion cmc
INNER JOIN lesson_modules cm ON cmc.lessonmoduleid = cm.id
INNER JOIN lesson_completion_settings ccc ON cm.lesson = ccc.lesson
INNER JOIN lesson c ON cm.lesson = c.id
INNER JOIN user u ON u.id = cmc.userid
WHERE ccc.criteriatype=4
GROUP BY c.name
I need the count of each user has Completed modules, Inprocess modules and Notstarted modules for each course, where getting the count of userids from table CC by taking courseia from table CM, get number of modules that an user has completed from each course.
(A course can have morethan one module and a course can have number of users attempted all modules, few modules or not attempted at all).
So, I need number of users - has done number of modules - in a course. (3 logics)
(COND1 i.e.,Completed.Users ) : If number of modules attempted is equal to number of modinstance from table CMS (ex: no. of modules attempted by a user per course= 9, no.modinstance = 9. Because 7 is not equal to 9, They are completed.)
(COND2 i.e.,Inprocess.Users ) : Number of modules attempted should be >0, but not equal to [count(modinstance) per course] (ex: no. of modules attempted by a user per course= 7 , no.modinstance = 9. Because 7 is not equal to 9, They are Inprocess.)
(COND2 i.e.,Nostart.Users ) : Number of modules attempted should be equal to 0, (ex: no. of modules attempted by a user per course= 0. They are Notstarted).
You can refer my query, It was all doing good, but I need the count of COND1, COND2, COND3
I need the OUTPUT :
lesson COND1 COND2 COND3
5 65 32 6
6 40 12 15
8 43 56 0
9 0 7 9

select lesson,sum(COND1) as COND1, sum(COND2) as COND2,sum(COND3) as COND3
from
(
SELECT c.name,
ccc.lesson,
CASE WHEN COUNT(distinct cmc.id) = COUNT(distinct ccc.id) THEN 1 ELSE 0 END AS "COND1",
CASE WHEN COUNT(distinct cmc.id) > 0 AND COUNT(distinct cmc.id) != COUNT(distinct ccc.id) THEN 2 ELSE 0 END AS "COND2",
CASE WHEN COUNT(distinct cmc.id) = 0 THEN 3 ELSE 0 END AS "COND3"
FROM
lesson_modules_completion cmc
INNER JOIN lesson_modules cm ON cmc.lessonmoduleid = cm.id
INNER JOIN lesson_completion_settings ccc ON cm.lesson = ccc.lesson
INNER JOIN lesson c ON cm.lesson = c.id
INNER JOIN user u ON u.id = cmc.userid
WHERE ccc.criteriatype=4
GROUP BY c.name,ccc.lesson
) t
group by lesson

Related

MySQL Where Clause with Union All getting wrong results

I will preface this by saying I am still very much learning MySQL, and I am absolutely at that stage where I know just enough to be dangerous.
I have a database with data for scorekeeping for a sports league. We record wins/losses as either 1 or zero points. There is a night that has double play involved (meaning the players play twice in a single night, for 2 different formats). My data is structured like so (just a sample, I have hundreds of rows, over different formats):
ID
FID
WK
Type
HomeTeam
AwayTeam
HF1
HF2
AF1
AF2
1
44
1
PL
TM1
TM2
1
0
0
1
2
44
1
PL
TM3
TM4
0
0
1
1
3
44
2
PL
TM2
TM3
1
1
0
0
4
44
2
PL
TM4
TM1
0
1
1
0
5
44
3
PL
TM3
TM1
999
0
999
1
6
44
3
PL
Tm2
TM4
1
0
0
1
Where the 999 is used as a code number for us to know that the match hasn't yet been played, or the scoresheet hasn't been turned in to us for recordkeeping. (I use PHP to call these to a website for users to see what is going on, and am using an IF statement to convert that 999 to "TBD" on the website)
I can pull the Format 1 and Format 2 scores separately and get a listing just fine, but when I try to pull them together and get a total score, I am getting an incorrect count. I know the error lies with my WHERE Clause, but I've been banging my head trying to get it to work correctly, and I think I just need an extra set of eyes on this.
My current SQL Query is as follows:
SELECT Team,
SUM(TotalF1) AS TotalF1,
SUM(TotalF2) AS TotalF2,
SUM(TotalF1+TotalF2) AS Total
FROM ( ( SELECT HomeTeam AS Team,
HF1 AS TotalF1,
HF2 AS TotalF2
FROM tbl_teamscores
WHERE FID = 44
AND Type = 'PL'
AND HF1 != 999
AND HF2 != 999 )
UNION ALL
( SELECT AwayTeam,
AF1,
AF2
FROM tbl_teamscores
WHERE FID = 44
AND Type = 'PL'
AND AF1 != 999
AND AF2 != 999 )
) CC
GROUP BY Team
ORDER BY Total desc, Team ASC;
I am getting incorrect totals though, and I know the reason is because of those 999 designations, as the WHERE clause is skipping over ALL lines where either home or away score matches 999.
I tried separating it out to 4 separate Select Statements, and unioning them, but I just get an error when I do that. I also tried using Inner Join, but MySQL doesn't seem to like that either.
Edit to add DBFiddle with Real World Table Data and queries: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1d4d090b08b8280e734218ba32db6d88
An example of the problem can be observed when looking at the data for Player 10. The overall total should be 13, but I am only getting 12.
Any suggestions would be very helpful.
Thanks in advance!
You can use conditional aggregation:
SELECT Team,
SUM(CASE WHEN Total8 <> 999 THEN Total8 END) AS Total8,
SUM(CASE WHEN TotalLO <> 999 THEN TotalLO END) AS TotalLO,
SUM(CASE WHEN Total8 <> 999 THEN Total8 END) + SUM(CASE WHEN TotalLO <> 999 THEN TotalLO END) AS Total
FROM (
SELECT HomeTeam AS Team, Home8PTS AS Total8, HomeLOPTS AS TotalLO FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
UNION ALL
SELECT AwayTeam, Away8PTS, AwayLOPTS FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
) CC
GROUP BY Team
ORDER BY Team ASC;
or:
SELECT Team,
SUM(NULLIF(Total8, 999)) AS Total8,
SUM(NULLIF(TotalLO, 999)) AS TotalLO,
SUM(NULLIF(Total8, 999)) + SUM(NULLIF(TotalLO, 999)) AS Total
FROM (
SELECT HomeTeam AS Team, Home8PTS AS Total8, HomeLOPTS AS TotalLO FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
UNION ALL
SELECT AwayTeam, Away8PTS, AwayLOPTS FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
) CC
GROUP BY Team
ORDER BY Team ASC;
If you get nulls in the results then you should also use COALESCE():
SELECT Team,
COALESCE(SUM(NULLIF(Total8, 999)), 0) AS Total8,
COALESCE(SUM(NULLIF(TotalLO, 999)), 0) AS TotalLO,
COALESCE(SUM(NULLIF(Total8, 999)), 0) + COALESCE(SUM(NULLIF(TotalLO, 999)), 0) AS Total
FROM (
SELECT HomeTeam AS Team, Home8PTS AS Total8, HomeLOPTS AS TotalLO FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
UNION ALL
SELECT AwayTeam, Away8PTS, AwayLOPTS FROM tbl_teamscores WHERE FID = 44 AND Type = 'PL'
) CC
GROUP BY Team
ORDER BY Team ASC;
See the demo.

how to get two table joined data exclude some conditional data of one table in mysql?

I have two tables: Student and fee
student
sid
name
roll_no
1
John
22
2
Karina
32
3
Navin
42
fee
fid
s_id
month
fee
1
2
January
1000
2
3
January
1200
3
2
Fabruary
1000
I want to get students (who not paid fee) for Fabruary : like this...
Student id
Name
Roll No
January
February
1
John
22
0
0
3
Navin
42
1200
0
My code is :
SELECT s.sid,s.name,s.roll_no,f.fee
from student s
left join
fee f
ON f.fid = s.sid
AND f.month = 'January'
where s.sid NOT IN (SELECT s_id from fee
where month = 'February')
order by c.id;
I got zero value in both months for all students
------Thanks in advance-------
After correction this code works in mysql workbench but not in java application.
SELECT
s.sid,s.name,s.roll_no, ifnull(f.fee,0) as pre_month,0 as current_month
from student s
left join
fee f
ON f.s_id = s.sid
AND f.month = 'January'
where s.sid NOT IN
(SELECT s_id from fee
where month = 'February')
order by s.sid;
For the results you want, I would suggest conditional aggregation and a having clause:
SELECT s.sid, s.name, s.roll_no,
SUM(CASE WHEN f.month = 'January' THEN f.fee ELSE 0 END) as january,
SUM(CASE WHEN f.month = 'February' THEN f.fee ELSE 0 END) as february
FROM student s LEFT JOIN
fee f
ON f.fid = s.sid AND f.month = 'January'
GROUP BY s.sid, s.name, s.roll_no
HAVING SUM(CASE WHEN f.month = 'February' THEN f.fee ELSE 0 END) = 0 AND
SUM(CASE WHEN f.month = 'January' THEN f.fee ELSE 0 END) > 0;
Here is a db<>fiddle.
Note that storing month names in a column is usually a really bad idea. It does not distinguish between the years, for instance. It is much better to use a date.
You can use a left join to join the students with their fees, and then a having clause to filter the list down to those who don't have one for February. The below query should get you a list of all students who did not pay a fee for February.
It also looked like you might be using the wrong column on the fee table for the join. It looked like you might want s_id instead of fid.
select s.*
from students s
left join fee f on f.s_id=s.sid and f.month='February'
having f.fid is null;

Transform duplicate rows in columns SQL

I have the following query:
SELECT folders.name folder, s.name `schedule`, ms.month as 'month', concat(s.start, " - ", s.end) `time`,
p.name 'profession', (select count(*) from employees where profession_id = p.id) as "count_employees"
FROM schedules s
JOIN folders ON folders.id = s.folder_id
JOIN month_schedules ms ON ms.schedule_id = s.id
LEFT JOIN schedule_professions sp ON sp.schedule_id = s.id
JOIN professions p ON p.id = sp.profession_id
WHERE s.company_id = 82 AND ms.year = 2021 AND ms.month = 2
This query returns the following table
folder
schedule
month
time
profession
count_employees
folder_a
schedule_a
2
0
profession_a
3
folder_a
schedule_a
2
0
profession_b
5
folder_a
schedule_a
2
0
profession_c
1
folder_a
schedule_b
2
0
profession_a
1
folder_a
schedule_b
2
0
profession_b
0
folder_a
schedule_b
2
0
profession_c
0
but what I want is this:
folder
schedule
month
time
profession_a
profession_b
profession_c
folder_a
schedule_a
2
0
3
5
1
folder_a
schedule_b
2
0
1
0
0
The number of professions is unknown, so has to be dynamically calculated.
I tried using GROUP_CONCAT and CONCAT, but I'm a newbie with SQL, so I didn't have any success.
SELECT
folders.name folder,
s.name `schedule`,
ms.month as 'month',
concat(s.start, " - ", s.end) `time`,
count(CASE WHEN p.name="profession_a" THEN 1 ELSE 0 END) 'profession_a',
count(CASE WHEN p.name="profession_b" THEN 1 ELSE 0 END) 'profession_b',
count(CASE WHEN p.name="profession_c" THEN 1 ELSE 0 END) 'profession_c',
(select count(*) from employees where profession_id = p.id) as "count_employees"
FROM schedules s
JOIN folders ON folders.id = s.folder_id
JOIN month_schedules ms ON ms.schedule_id = s.id
LEFT JOIN schedule_professions sp ON sp.schedule_id = s.id
JOIN professions p ON p.id = sp.profession_id
WHERE s.company_id = 82 AND ms.year = 2021 AND ms.month = 2
You only need to check if the GROUP BY is correct, i did not do that check.... 😉

How resolve null value when create view

I need to create a view like this:
STUDENT JANUARY FEBRUARY MARCH ........ DECEMBER
miki 10.23 23.23 0 0
Goku 10 0 0 0
Luffy 0 0 0 0
I have a table studentMovement(id_studentmovement,id_student,month,year,cost,date,id_university,university_name)
that represents every sigle cost for the student in this month and year. it contains the real cost that some students had done in a certain course in a certain university.
Table Students(id_student,name)
Table University(id_university,university name);
I want to get for all university, all student and for single student the cost for every months ( also if the student doesn't spent anything in a certain university:
This sql query is this:
select year(sm.date) as year, s.id_student, s.name,
sum(amount) as year_amount,
sum(case when month(sm.date) = 1 then amount else 0 end) as january,
sum(case when month(sm.date) = 2 then amount else 0 end) as february,
. . .
sum(case when month(sm.date) = 12 then amount else 0 end) as december,
u.id_university as id_university,
u.university_name as university_name
from ((schema.students s left join
schema.studentMovement sm
on s.d_student = sm.id_student ) inner join schema.university u on u.id_university=sm.id_university)
group by year(sm.date) as year, s.id_student, s.name, u.id_university,
u.university_name
THe query put wrong value and some value are null.Anyone can help me?
Null values appear from your do Left Join Statement. Because it returns all records from the left table, and the matched records from the right table. The result is NULL from the right side, if there is no match.
select
year(sm.date) as year,
s.id_student,
s.name,
sum(amount) as year_amount,
sum(case when month(sm.date) = 1 then amount else 0 end) as january,
sum(case when month(sm.date) = 2 then amount else 0 end) as february,
. . .
sum(case when month(sm.date) = 12 then amount else 0 end) as december,
u.id_university as id_university,
u.university_name as university_name
from
((schema.students s
inner join schema.studentMovement sm on s.d_student = sm.id_student )
inner join schema.university u on u.id_university=sm.id_university)
group by
year(sm.date),
s.id_student,
s.name,
u.id_university,
u.university_name
If you want to not see Null change your Left Join to Inner Join instead because Inner Join selects records that have matching values in both tables.
Try just using inner joins in the from clause:
FROM schema.students s JOIN
schema.studentMovement sm
ON s.d_student = sm.id_student JOIN
schema.university u
ON u.id_university = sm.id_university
Maybe you noticed some wrong values in the amount field: try to delete the double quotes
COALESCE(SUM(sm.amount), 0) AS amount,

MySQL where statement after left join

I am writing a hockey stat database. I have the need to calculate how many players were on the ice when a goal is scored.
I have set up the following sqlfiddle:
http://sqlfiddle.com/#!9/ed8fa
problem I am having is how to filter the results such that only goals that are scored at regular strength (shot type "reg") or goals that are scored while shorthanded (shot type "sh") count towards this total.
I need all players to be listed in the output, even if their number is zero. After finding the players "Plus rating", I will calculate each players "minus rating" and subtract the two. Once I figure out how to accurately find the "Plus rating", I should be able to figure out how to do the rest.
For the given data in the sqlfiddle, the desired output should be:
player_id Plus_count
20 1
21 0
22 2
23 1
24 1
25 0
26 1
27 1
28 1
29 0
30 0
31 2
32 1
33 0
I am having trouble figuring out how the join would work such that I can use where to filter out all goals that are "pp".
Thanks for any pointers you might be able to give...
adding what I have tried. This is from my dev db, so just slightly different from the sqlfiddle:
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
left join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf on sf.fk_player_id = players.player_id
union
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
right join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf2 on sf2.fk_player_id = players.player_id
left join goals_for on goals_for.fk_shot_for_id = sf2.shot_for_id
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh'
you can see my various attempts above to use the where to eliminate the "pp" goals.