I am having 3 tables - student, department and exam_results. What I am trying to do here is to select all of the department/s name/s which have the highest grade for example 6.
I have tried the following query but in this example's case where we have 2 departments with grade 6 but the Informatics one has 2 max grades and Chemistry has only 1 I am still retrieving the Chemistry department name which should not be returned but only the Chemistry department name(also if we have 2 max grades for Chemistry we should be able to retrieve both Informatics and Chemistry records).
SELECT department
FROM (SELECT d.department_name as department, count(e_r.grade) as cnt
FROM exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
WHERE e_r.grade = 6
GROUP BY d.department_name
) as ex;
Also with the following query I was able to accomplish to retrieve the department/s name/s and the count of the given 'n' grade in the WHERE clause but for some reason I am not able to accomplish what I really want.
SELECT department_name, max(cnt) as cnt
FROM (SELECT d.department_name as department_name, e_r.grade, count(e_r.grade) as cnt
FROM exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
WHERE grade = 6
GROUP BY d.department_name, e_r.grade
) AS ex
GROUP BY department_name;
Providing a dbfiddle link with the explained example: https://dbfiddle.uk/siEjfNXP
Would be glad to receive any suggestions or hints on how to achieve this, thank you!
Here are the tables with example values(all included in dbfiddle link):
Student table:
student_id
department_id
1
1
2
1
3
2
4
2
5
3
6
3
7
4
8
4
9
5
10
5
Department table:
department_id
department_name
1
Informatics
2
Biology
3
Physics
4
Geography
5
Chemistry
Exam_results table:
student_id
grade
1
6
2
6
3
4
4
4
5
3
6
3
7
2
8
2
9
6
10
5
In case you want a mire flexible solitution if the ighest ranks are not 6
WITH CTE as
(SELECT
d.department_name as department_name,e_r.grade, count(e_r.grade) as cnt
, DENSE_RANK() OVER (ORDER BY e_r.grade DESC ,count(e_r.grade) DESC) rk
FROM exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
WHERE (d.department_name,e_r.grade) IN
(select d.department_name as department_name, MAX(e_r.grade)
from exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
group by d.department_name)
group by d.department_name, e_r.grade)
SELECT department_name,grade,cnt FROM CTE WHERE rk = 1
department_name
grade
cnt
Informatics
6
2
fiddle
Given you want only one row (the department with most biggest grade), you can order by your count of grades descendently, then limit rows to 1.
SELECT d.department_name as department
FROM exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
WHERE e_r.grade = 6
GROUP BY d.department_name
ORDER BY COUNT(e_r.grade) DESC
LIMIT 1
Check the demo here.
If you're allowing more than one max value, you can use the DENSE_RANK window function to assign a ranking order to your counts, then get all the records that have denserank = 1.
SELECT department
FROM (SELECT d.department_name as department,
DENSE_RANK() OVER(ORDER BY COUNT(e_r.grade) DESC) AS rn
FROM exam_results e_r
INNER JOIN students s ON e_r.student_id = s.student_id
INNER JOIN department d ON s.department_id = d.department_id
WHERE e_r.grade = 6
GROUP BY d.department_name
) AS ex
WHERE rn = 1
Check the demo here.
Related
If I remove the group by statement, then it is showing an error.
SELECT COMPANY.COMPANY_CODE,
company.founder,
count(distinct lm.lead_manager_code),
count(distinct sm.senior_manager_code),
count(distinct m.manager_code),
count(distinct e.employee_code)
from Company
join Lead_Manager as lm on Company.company_code = lm.company_code
join Senior_Manager as sm on Company.company_code = sm.company_code
join Manager as m on Company.company_code = m.company_code
join Employee as e on Company.company_code = e.company_code
GROUP BY Company.COMPANY_CODE, Company.FOUNDER
ORDER BY Company.COMPANY_CODE ASC
Basically, you are using an aggregate function so you need to group
select count(amount) from Orders group by customer_id
Orders
order_id item amount customer_id
1 Keyboard 400 4
2 Mouse 300 4
3 Monitor 12000 3
4 Keyboard 400 1
5 Mousepad 250 2
Now using group by on customer_id so we have id 4 so need to check the count of 4 id with group by
i have the data like this:
table students
studentid studentname
1 ani
2 budi
3 caca
4 dedi
.... ...
table subjects
subjectid subjectname
1 MATH
2 ENG
3 SCIENCE
4 ART
.... ...
table scores
studentid subjectname score
1 1 90
2 2 80
3 3 77
4 4 80
.... ... ...
i want to get:
which subject has the 2nd highest score of all test results. Show the name of the subject and the score.
expected result :
subjectname score
ENG 80
ART 80
i have try this query:
SELECT st.studentname, su.subjectname, MAX(sc.score)
FROM scores sc
left join subjects su on su.subjectid = sc.subjectid
left join students st on st.studentid = sc.studentid
WHERE score<>(
SELECT MAX(score)
FROM scores);
but the output:
subjectname score
ENG 80
how can i handle this ?
Print every student who had scored lower than the subject’s average score per student.
Show the name of the student,
name of the subject,
average score per student of the subject,
the student’s score.
my query was:
SELECT st.studentname, su.subjectname, avg(score), sc.score
FROM scores sc
left join subjects su on su.subjectid = sc.subjectid
left join students st on st.studentid = sc.studentid
WHERE score <
(SELECT AVG(score)
FROM scores );
but the result wrong, the average show the avg of all subject not per subject.
how can u handle ?
Since there are ties in the scores one way to get the 2nd highest score is with this query:
select max(score)
from scores
where score < (select max(score) from scores)
Now join subjects and scores (students is not needed) and use the above query in the WHERE clause to get the subjects with that score:
select sb.subjectname, sc.score
from subjects sb inner join scores sc
on sc.subjectid = sb.subjectid
where sc.score = (
select max(score)
from scores
where score < (select max(score) from scores)
)
See the demo.
Results:
> subjectname | score
> :---------- | ----:
> ENG | 80
> ART | 80
For the 2nd question, this query:
select subjectid, avg(score) avg_score
from scores
group by subjectid
returns the average score of all subjects and you can join it to the 3 tables:
select st.studentname, sb.subjectname, t.avg_score
from students st
inner join scores sc on sc.studentid = st.studentid
inner join subjects sb on sb.subjectid = sc.subjectid
inner join (
select subjectid, avg(score) avg_score
from scores
group by subjectid
) t on t.subjectid = sb.subjectid and t.avg_score > sc.score
Use window functions:
SELECT subjectname, avg_score
FROM (SELECT su.subjectname, AVG(sc.score) as avg_score,
DENSE_RANK() OVER (ORDER BY AVG(sc.score) DESC) as ranking
FROM scores sc JOIN
subjects su
ON su.subjectid = sc.subjectid
GROUP BY su.subjectname
) s
WHERE ranking = 2;
SELECT st.studentname, su.subjectname, sc.score
FROM scores sc
left join subjects su on su.subjectid = sc.subjectid
left join students st on st.studentid = sc.studentid
WHERE sc.score < AVG(sc.score)
GROUP BY st.studentname,su.subjectname
Here is my SQL query and result. My requirement is to display department_name with a maximum staff count but I don't know how to do that.
I want a result like department_name - SE and staff_ count - 4 only.
select d.department_name, count(staff_id) from department d, staff sf
where d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc
DEPARTMENT_NAME COUNT(SF.STAFF_ID)
------------------------------ ------------------
SE 4
EEE 2
IT 2
CSE 2
ECE 1
You need to first get the count of each department and then select department with the maximum count. Therefore, you can use sub-query as following:
SELECT d_name, MAX (staff_cnt)
FROM (SELECT d.department_name as d_name, count(staff_id) as staff_cnt
FROM department d, staff sf
WHERE d.department_id = sf.staff_id
GROUP BY department_name);
Try this
alias query
select d.department_name, count(staff_id)
from department d, staff sf
where d.department_id = sf.staff_id AND d.department_name = 'SE'
group by department_name
order by count(staff_id) desc
JOIN Query
select d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
WHERE d.department_name = 'SE'
group by department_name
order by count(staff_id) desc
LIMIT 1
OR Top
select TOP 1 d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc
You should use LIMIT 1 for reduce the result but also use explicit join syntax for a better readability:
select d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc
limit 1
Or without using limit you could try having on the max:
select d.department_name, count(staff_id) count_staff
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
having count_staff = (
select max(count_staff)
from ( select d.department_name, count(staff_id) count_staff
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name ) t
)
I need to select 8 people from a movie crew. I only want to have 3 producers and then let the query continue with other jobs.
This is my query now:
SELECT EmployeeID, j.NameEN, e.Firstname, e.Lastname, j.ID AS JobId
FROM crew AS c
LEFT JOIN job AS j ON c.JobID = j.ID
LEFT JOIN employee AS e ON c.EmployeeID = e.Id
WHERE c.MovieID = 237038
ORDER BY j.SortOrder ASC, c.JobID ASC, e.Score DESC
LIMIT 8
How can I achieve selecting only 3 employee's with the same job id?
Sample output
EmployeeID NameEN Firstname Lastname JobId
802 Director Chris Columbus 2
5707 Director David Yates 2
1705 Director Mike Newell 2
175 Director Alfonso Cuarón 2
5115 Writer Steve Kloves 3
2041 Writer Michael Goldenberg 3
11096 Writer J.K. Rowling 3
You can see here that I have 4 Directors. The desired output would be that there were 3 Directors max.
I think the simplest method for your particular problem is union all:
(SELECT EmployeeID, j.NameEN, e.Firstname, e.Lastname, j.ID AS JobId
FROM crew c LFT JOIN
job j
ON c.JobID = j.ID LEFT JOIN
employee e
ON c.EmployeeID = e.Id
WHERE c.MovieID = 237038 AND
j.NameEN = 'Producer'
ORDER BY j.SortOrder ASC, c.JobID ASC, e.Score DESC
LIMIT 3
) UNION ALL
(SELECT EmployeeID, j.NameEN, e.Firstname, e.Lastname, j.ID AS JobId
FROM crew c LFT JOIN
job j
ON c.JobID = j.ID LEFT JOIN
employee e
ON c.EmployeeID = e.Id
WHERE c.MovieID = 237038 AND
j.NameEN <> 'Producer'
ORDER BY j.SortOrder ASC, c.JobID ASC, e.Score DESC
LIMIT 5
);
I have 3 tables
Quality
id name
----------
1 bold
2 Frank
3 Quite
4 friendly
Student
id name
---------
1 A
2 B
3 C
StudentQuality
id fk_qual fk_stud
1 1 1
2 2 1
3 1 2
4 2 2
5 3 2
6 1 3
7 2 3
8 3 3
9 4 3
These are my tables. How do I get the students who are bold, frank and quite.
If I use IN operation, I get all the 3 students, I need to get only 2 students
If I use bold, frank, I should get all the 3 students
If I use bold, frank, quite and friendly, I should get all the 1 students
So how to query this.
you could do it like:
Declaring a table variable, holding the values you're searching for
Selecting the data and using your table variable as a condition for the INNER JOIN and counting the values of the table variable and compare them to the amount of qualities
Like:
DECLARE #qualities table(qname varchar(100));
INSERT INTO #qualities
VALUES ('bold'),('Frank'),('Quite');
SELECT S.name
FROM Student S
INNER JOIN StudentQuality SQ
ON S.id = SQ.fk_stud
INNER JOIN Quality Q
ON SQ.fk_qual = Q.id
AND Q.name in (SELECT qname FROM #qualities)
GROUP BY S.name
HAVING count(*) = (SELECT COUNT(qname) FROM #qualities)
SELECT *
FROM Student
WHERE id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('bold')
)
INTERSECT
SELECT *
FROM Student
WHERE id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('frank')
)
INTERSECT
SELECT *
FROM Student
WHERE id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('quite')
)
or without INTERSECT
SELECT *
FROM Student
WHERE id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('bold')
) and id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('frank')
) and id IN
(
SELECT fk_stud
FROM StudentQuality sq
JOIN Quality q ON sq.fk_qual = q.id
WHERE q.name IN ('quite')
)
Another variation
SELECT s.id,min(s.name) studentname FROM student s
INNER JOIN (studentquality sq INNER JOIN quality q ON q.id=sq.fk_qual)
ON sq.fk_stud=s.id WHERE q.name in ('bold','frank','quite') group by s.id
having length(group_concat(q.name))=length(concat('bold,','frank,','quite'));
SELECT s.id,min(s.name) studentname, (group_concat(q.name)) qname FROM student s
INNER JOIN (studentquality sq INNER JOIN quality q ON q.id=sq.fk_qual)
ON sq.fk_stud=s.id WHERE q.name in ('bold','frank','quite') group by s.id
having length(qname)=length(concat('bold,','frank,','quite'));