MYSQL WHERE NOT query - mysql

I'm working on a project where teachers can assign badges to students, it's similar to an achievement system.
Now I'm trying to get an overview of students who DON'T have a specific badge, but the queries I use are not working.
I made a table called StudentHasBadge, in which the studentnumber and badge_id are saved.
Example:
I want to show a list of students (s.studentnumber, s.firstname, s.lastname) that doens't have the "English: Reading" badge.
I use the following query:
(English: Reading has badge_id 61 in my database)
SELECT DISTINCT s.studentnumber, s.firstname, s.lastname
FROM students s INNER JOIN student_has_badge shb
ON s.studentnumber = shb.studentnumber
WHERE NOT shb.badge_id = 61
As results I also get students who earned the badge
I also tried != instead of WHERE NOT, but it doesn't give me a different result

You can use a LEFT JOIN and check for no match:
SELECT s.studentnumber, s.firstname, s.lastname
FROM students s LEFT JOIN
student_has_badge shb
ON s.studentnumber = shb.studentnumber AND shb.badge_id = 61
WHERE shb.studentnumber IS NULL;

You should use NOT EXISTS:
SELECT s.studentnumber, s.firstname, s.lastname
FROM students s
WHERE NOT EXISTS(SELECT 1 FROM student_has_badge
WHERE studentnumber = s.studentnumber
AND badge_id = 61);

Don't need the word NOT. Just the parameter of <> or =!
SELECT DISTINCT s.studentnumber,
s.firstname,
s.lastname
FROM students s
JOIN student_has_badge shb ON s.studentnumber = shb.studentnumber
WHERE
shb.badge_id <> 61

Related

Select records that are not associated with the other record

Hi i have 3 tables Modules,Students and join table (many to many) StudentModules.I want to select all modules that the student has not registered for.When the student register the information is stored in the StudentModules table.Basically i want to select all modules that are not associated with the student number in the StudentModules table from the Modules table.
i have tried the following code
SELECT Modules.*, Students.*
FROM ((StudentsModules INNER JOIN
Modules ON StudentsModules.ModuleCode = Modules.ModuleCode) INNER JOIN
Students ON StudentsModules.StudentNo = Students.StudentNo)
Where StudentNo = 48377767 AND WHERE ModuleCode NOT IN (SELECT ModuleCode FROM StudentsModules)
You're close, you forgot one check at the end!
Edit this part:
NOT IN (SELECT ModuleCode FROM StudentsModules where StudentNo=48377767)
One possible way to select all modules that the student has not registered for, assuming that the student no is 48377767 in this example :
SELECT m.*
FROM Modules m
LEFT JOIN StudentsModules sm ON sm.ModuleCode = m.ModuleCode
AND sm.StudentNo = 48377767
WHERE sm.ModuleCode IS NULL
[SQL Fiddle]
UPDATE :
Different approach without JOIN :
SELECT m.*
FROM Modules m
WHERE m.ModuleCode NOT IN
(
SELECT ModuleCode
FROM StudentsModules
WHERE StudentNo = 48377767
)

how to display multiple values, separated by commas, at single columns?

I am using mysql to perform queries. have the following 7 tables.
appointment //non-atomic, eg. values -> 1,7,3
gender //atomic value
module //non-atomic, eg. values -> 12,33
program
rank
staff
student
I have tried 'concat', 'find_in_set' & 'in' functions but cannot get it to work. How may I display multiple values # relations 'appointment' & 'module'?
The following statement is the closest i can get. Please let me know if additional details are required, thank you.
SELECT sta.staName
, r.rank
, sta.appointmentID
, a.appointment
, m.moduleCode
FROM staff AS sta
JOIN rank AS r
ON (sta.rankID = r.rankID)
JOIN appointment AS a
ON (sta.appointmentID = a.appointmentID)
JOIN module AS m
ON (sta.teachModuleID = m.moduleID)
WHERE sta.genderID = 1;
SELECT sta.staName, r.rank, sta.appointmentID,
group_concat(distinct a.appointment) as appointments,
group_concat(distinct m.moduleCode) as moduleCodes
FROM staff AS sta
INNER JOIN rank AS r ON sta.rankID = r.rankID
INNER JOIN appointment AS a ON find_in_set(sta.appointmentID, a.appointmentID) > 0
INNER JOIN module AS m ON find_in_set(sta.teachModuleID, m.moduleID) > 0
WHERE sta.genderID = 1
GROUP BY sta.staName, r.rank, sta.appointmentID

How to get multi columns via subquery?

I want to get members and their photos. Every member has 2 photos. (I am not talking about profile image)
There are 2 tables named as Members and MemberPhotos.
Here is my query which doesn't work(expectedly):
SELECT
M.Name as MemberName,
M.LastName as MemberLastName,
(
SELECT
TOP 1
MP.PhotoName
FROM
MemberPhotos MP
WHERE
MP.MemberID = M.ID
AND
MP.IsFirst = 1
) as MemberFirstPhoto,
(
SELECT
TOP 1
MP.PhotoName
FROM
MemberPhotos MP
WHERE
MP.MemberID = M.ID
AND
MP.IsFirst = 0
) as MemberSecondPhoto,
FROM
Members M
Maybe somebody going to say that I should use inner join instead, I don't want to use inner join, if I use it I get data multiple like:
Name Surname PhotoName
Bill Gates bill.png
Bill Gates bill2.png
Steve Jobs steve.jpg
Steve Jobs steve2.jpg
What do you recommend me about query?
Thanks.
EDIT:
Here is the output I want to get:
Name Surname FirstPhoto SecondPhoto
Bill Gates bill.png bill2.png
Steve Jobs steve.jpg steve2.png
The only issue with your example query is that you have an extra comma after
as MemberSecondPhoto
If you remove this it works fine.
SQL Fiddle with demo.
However, while that query is working now, because you know that each member only has two photos, you can use a much simpler query:
SELECT
M.Name as MemberName,
M.LastName as MemberLastName,
MPF.PhotoName as MemberFirstPhoto,
MPS.PhotoName as MemberSecondPhoto
FROM Members M
LEFT JOIN MemberPhotos MPF ON M.ID = MPF.MemberID AND MPF.IsFirst = 1
LEFT JOIN MemberPhotos MPS ON M.ID = MPS.MemberID AND MPS.IsFirst = 0
SQL Fiddle with demo.

GROUP_CONCAT not merging field

I have a syntax issue with my use of GROUP_CONTACT.
With a sql statement that looks like this:
SELECT
s.school_code
, s.school_name
,st.subject
,sg.subgroup
,GROUP_CONCAT(IF(r.year=2012,a.proficiency_index,NULL)) AS pi_2012
,GROUP_CONCAT(IF(r.year=2013,a.proficiency_index,NULL)) AS pi_2013
FROM
ayp_data a
INNER JOIN
report_year r ON
a.report_year_id = r.id
INNER JOIN
school s ON
a.school_code_id = s.id
INNER JOIN
sub_group sg ON
a.subgroup_id = sg.id
INNER JOIN
`subject` st ON
a.subject_id = st.id
GROUP BY
report_year_id,
s.school_code
, s.school_name
,st.subject
,sg.subgroup
HAVING
s.school_name = 'Moody Elementary School' AND
`subject` = 'Mathematics' AND
`subgroup` = 'All Students'
I am getting results like this:
SCHOOL_CODE SCHOOL_NAME SUBJECT SUBGROUP PI_2012 PI_2013
0065 Moody Elementary School Mathematics All Students 9.640000343322754 (null)
0065 Moody Elementary School Mathematics All Students (null) 10.920000076293945
I want to merge the two rows into one and put non-null field values PI_2012 and PI_2013 on the same line.
I thought I could do that with GROUP_CONTACT; but it's not doing as I thought it would.
How could I use GROUP_CONCAT to merge these fields?
Or, is there an even smarter way to do this?
I have the full schema and query here on SQL Fiddle.
If you don't want separate years to appear in separate rows, then you need to remove report_year_id from the GROUP BY clause. That is — you need to change this:
GROUP BY
report_year_id,
s.school_code
, s.school_name
,st.subject
,sg.subgroup
to this:
GROUP BY
s.school_code
, s.school_name
,st.subject
,sg.subgroup

Get list of students with max number in each class

I want to get the list of students from db, who have get maximum number in each class with student name. Using MySQL DB.
I have the following tables like Student, classes, result (with different years results)
Tables structure student(student_id,student_name,class_id,address), class(class_id,class_name), results(result_id,student_id,year,marks)
and I need list like
Student Name class Marks
Jon A-1 800
Steve B-1 789
Edit corrected code, comment was correct
Try the code on this SQL Fiddle link
You could use a subquery to filter the students with the highest mark per class:
select s.student_name
, c.class_name
, r.marks
from results r
join student s
on r.student_id = s.student_id
join class c
on c.class_id = s.class_id
where r.result_id =
(
select r2.result_id
from student s2
join results r2
on s2.student_id = r2.student_id
where c.class_id = s2.class_id
order by
r2.marks desc
limit 1
)
Live example at SQL Fiddle.
select s1.student_name, c1.class_name, r1.marks
from student s1, class c1, results r1,
(select s2.class_id, max(r2.marks) marks
from results r2, student s2
where r2.student_id = s2.student_id
group by s2.class_id) agg
where r1.marks = agg.marks
and r1.student_id = s1.student_id
and s1.class_id = c1.class_id
and s1.class_id = agg.class_id