HAVING MAX(COUNT(*)) not working - sql

I have the following code:
SELECT e.Student_ID, s.Name, s.Surname, Result_IS, COUNT(*)
FROM Students s
LEFT JOIN Exams e
ON e.Student_ID=s.Student_ID
WHERE Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
HAVING COUNT(*)=
(
SELECT MAX(COUNT(*)) FROM Exams
WHERE Student_ID=e.Student_ID
AND Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
)
I'm having problem with the HAVING COUNT(*) which should select the row where the COUNT(*) gave the biggest result, but instead it just giving me the output of the first select, which is the following:
I've been trying all sort of things but nothing works to select the row, where count is the maximum.
Just give me a hint please in which direction should I move from here, and what is wrong with the code.

Do
HAVING COUNT(*)=
(
SELECT MAX(COUNT(*)) FROM Exams
WHERE Student_ID=e.Student_ID
AND Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
)
query on the joined table. :)

Why not just order by count(*) desc and select top 1?
SELECT top 1 e.Student_ID, s.Name, s.Surname, Result_IS, COUNT(*) FROM Students s LEFT JOIN Exams e
ON e.Student_ID=s.Student_ID
WHERE Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
order by count(*) desc
I think this is the syntax for Oracle
Select * FROM
(
SELECT e.Student_ID, s.Name, s.Surname, Result_IS, COUNT(*) FROM Students s LEFT JOIN Exams e
ON e.Student_ID=s.Student_ID
WHERE Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
order by count(*) desc
)
Where rownum=1

So, I found out how to do it, the solution is the following:
SELECT e.Student_ID, s.Name, s.Surname, Result_IS, COUNT(*) FROM Students s LEFT JOIN Exams e
ON e.Student_ID=s.Student_ID
WHERE Result_IS='Negative'
GROUP BY e.Student_ID, s.Name, s.Surname, Result_IS
HAVING COUNT(*)=
(
SELECT MAX(count) from
(
SELECT count(*) as count FROM Exams
WHERE Result_Is='Negative'
GROUP BY Student_ID
)
)

Related

How to add the count from one query into another query

My first query looks like this:
SELECT location, COUNT(*) as sections
FROM section
GROUP BY location
which gives me:
Simply join the queries:
SELECT *
FROM
(
SELECT location, COUNT(*) as sections
FROM section
GROUP BY location
)
FULL OUTER JOIN
(
SELECT s.location, COUNT(*) as students
FROM enrollment e
INNER JOIN section s ON s.section_id = e.section_id
GROUP BY s.location
) USING (location)
ORDER BY location;
Another option is to group the enrollments by section, join and group by location then.
SELECT
location,
COUNT(*) as sections,
SUM(students_in_section) AS students
FROM section s
LEFT JOIN
(
SELECT section_id, COUNT(*) as students_in_section
FROM enrollment
GROUP BY section_id
) e ON e.section_id = s.section_id
GROUP BY s.location
ORDER BY s.location;
Another option is to join the tables and count distinct sections and distinct enrollments.
SELECT
location,
COUNT(DISTINCT s.section_id) as sections,
COUNT(DISTINCT e.enrollment_id) AS students
FROM section s
LEFT JOIN enrollment e ON e.section_id = s.section_id
GROUP BY s.location
ORDER BY s.location;
You can use COUNT(DISTINCT ...) to count the unique sections for each location
SELECT location, COUNT (DISTINCT s.section_id) AS sections, COUNT (*) AS students
FROM enrollment e INNER JOIN section s ON s.section_id = e.section_id
GROUP BY location

What is the alternative for ALL and EVERY in SQLite?

Hey im new to SQL and I'm trying to find the names of students enrolled in the maximum number of classes using SQLite on sqliteonline.com
These are the relations:
This is what I have:
SELECT S.sname
FROM Student S
WHERE S.snum IN (SELECT E.snum
FROM Enrolled E
GROUP BY E.snum
HAVING COUNT (*) >= ALL (SELECT COUNT (*)
FROM Enrolled E2
GROUP BY E2.snum ))
AND this is the error that I get:
I'm guessing the ALL keyword doesn't exist in SQLite or is used differently so I'm wondering what I should do next.
I'm also having the same problem with the EVERY keyword.
What I'm trying to solve:
For each faculty member that has taught classes only in room R128, print the faculty
member's name and the total number of classes she or he has taught.
What I have:
SELECT F.fname, COUNT(*) AS CourseCount
FROM Faculty F, Class C
WHERE F.fid = C.fid
GROUP BY F.fid, F.fname
HAVING EVERY ( C.room = "R128" )
What I get:
You can use ORDER BY and LIMIT:
SELECT S.sname
FROM Student S
WHERE S.snum IN (SELECT E.snum
FROM Enrolled E
GROUP BY E.snum
HAVING COUNT(*) = (SELECT COUNT(*)
FROM Enrolled E2
GROUP BY E2.snum
ORDER BY COUNT(*) DESC
LIMIT 1
)
);
Note: There are other ways to express the query logic. This specifically addresses the question that you asked.
One option uses window functions:
select s.name
from student s
inner join (
select snum, rank() over(order by count(*) desc) rn
from enrolled e
group by snum
) e on e.snum = s.snum
where rn = 1
If your version of SQLite does not support window functions (which were added in version 3.25), I would recommend a join and filtering with a having clause:
select s.name
from students s
inner join enrolled e on e.snum = s.snum
group by s.snum, s.name
having count(*) = (
select count(*)
from enrolled
group by snum
order by count(*) desc limit 1
)

Northwind - List of top ten employees

I have another trouble with my SQL queries.
My task is to create a list of top 10 employees, with the most sales in 1997.
So far I have this, simple query that shows me list of employees and which order they've sold.
SELECT
Orders.EmployeeID,
Orders.OrderID
FROM
Employees
JOIN
Orders ON Orders.EmployeeID = Employees.EmployeeID
ORDER BY
Orders.EmployeeID;
Now I want to group up those numbers, I need to know how many sales each employee did in 1997. How to do that?
You can get the results that you need without JOIN and GROUP BY if you order by results of a subquery:
SELECT TOP 10 *
FROM Employees e
ORDER BY (
SELECT COUNT(*)
FROM Sales s
WHERE s.EmployeeId=e.EmployeeId
AND DATEPART(year, o.OrderDate)=1997
) DESC
This yields top ten employees by the number of sales transactions.
If you need anything from Sales, say, the count, you would need to go the GROUP BY route:
SELECT TOP 10 * FROM (
SELECT e.EmployeeId, COUNT(*) AS SalesCount
FROM Employees e
LEFT OUTER JOIN Orders o ON o.EmployeeId=e.EmployeeId
AND DATEPART(year, o.OrderDate)=1997
GROUP BY e.EmployeeId
) groups
ORDER BY SalesCount DESC
WITH CTE AS
(
SELECT EmployeeId,COUNT(*) as cn,
DENSE_RANK(ORDER BY COUNT(*) DESC) AS rn
FROM orders
WHERE DATEPART(year,OrderDate)=1997
GROUP BY EmployeeId
)
SELECT e.*,COALESCE(o.cn,0) AS CountOrders
FROM Employees e
LEFT JOIN CTE o
ON e.EmployeeId=o.EmployeeId
WHERE o.rn<=10
It can reduce to this
SELECT top(10) EmployeeID, count(*) as cnt
FROM Orders
group by EmployeeID
ORDER BY count(*) desc;

SQL group function nested too deeply

I'm trying to create an sql query that will return the smallest occurrence of an id appearing between two tables however I keep getting the error with the line HAVING MIN(COUNT(E.C_SE_ID)). Oracle is saying that the group by function is nested too deeply.
I cannot think of another way of returning C_SE_ID
SELECT CS.C_SE_ID, MIN(COUNT(E.C_SE_ID))
FROM COURSE_SECTION CS, ENROLLMENT E, LOCATION L
WHERE CS.C_SE_ID=E.C_SE_ID
AND CS.LOC_ID=L.LOC_ID
AND L.BLDG_CODE='DBW'
GROUP BY CS.C_SE_ID
HAVING MIN(COUNT(E.C_SE_ID));
in enrollment table s_id and c_se_id are linked, I'm trying to get all the s_id that are related to that c_se_id. with the updated query oracle doesn't like the select * (for obvious reasons) but when I change it too e.c_Se_id I get nothing.
SELECT E.S_ID
FROM COURSE_SECTION CS, ENROLLMENT E
WHERE CS.C_SE_ID=E.C_SE_ID
AND E.C_SE_ID =(
select *
from (select CS.C_SE_ID, count(*) as cnt,
max(count(*)) over (partition by cs.c_se_id) as maxcnt
from COURSE_SECTION CS join
ENROLLMENT E
on CS.C_SE_ID=E.C_SE_ID join
LOCATION L
on CS.LOC_ID=L.LOC_ID
where L.BLDG_CODE='DBW'
GROUP BY CS.C_SE_ID
order by count(*) desc
) t
where cnt = maxcnt);
One way to do this is by nesting your query and then choosing the first row in the output:
select C_SE_ID, cnt
from (select CS.C_SE_ID, count(*) as cnt
from COURSE_SECTION CS join
ENROLLMENT E
on CS.C_SE_ID=E.C_SE_ID join
LOCATION L
on CS.LOC_ID=L.LOC_ID
where L.BLDG_CODE='DBW'
GROUP BY CS.C_SE_ID
order by count(*) desc
) t
where rownum = 1
Note I updated the join syntax to the more modern version using on instead of where.
If you want all minimum values (and there are more than one), then I would use analytic functions. It is a very similar idea to your original query:
select *
from (select CS.C_SE_ID, count(*) as cnt,
max(count(*)) over (partition by cs.c_se_id) as maxcnt
from COURSE_SECTION CS join
ENROLLMENT E
on CS.C_SE_ID=E.C_SE_ID join
LOCATION L
on CS.LOC_ID=L.LOC_ID
where L.BLDG_CODE='DBW'
GROUP BY CS.C_SE_ID
order by count(*) desc
) t
where cnt = maxcnt;
Try this instead of your original query:
SELECT E.S_ID
FROM ENROLLMENT E
where E.C_SE_ID in (select C_SE_ID
from (select CS.C_SE_ID, count(*) as cnt,
max(count(*)) over (partition by cs.c_se_id) as maxcnt
from ENROLLMENT E
LOCATION L
on CS.LOC_ID=L.LOC_ID
where L.BLDG_CODE='DBW'
GROUP BY e.C_SE_ID
) t
where cnt = maxcnt)
);
In addition to fixing the joins, I also removed all references to course_section. This table doesn't seem to be used (unless for filtering results), and removing it implifies the queries.

Help with SQL QUERY OF JOIN+COUNT+MAX

I need a help constructung an sql query for mysql database. 2 Table as follows:
tblcities (id,name)
tblmembers(id,name,city_id)
Now I want to retrieve the 'city' details that has maximum number of 'members'.
Regards
SELECT tblcities.id, tblcities.name, COUNT(tblmembers.id) AS member_count
FROM tblcities
LEFT JOIN tblmembers ON tblcities.id = tblmembers.city_id
GROUP BY tblcities.id
ORDER BY member_count DESC
LIMIT 1
Basically: retrieve all cities and count how many members each has, sort by that member count in descending order, making the highest count first - then show only that first city.
Terrible, but that's a way of doing it:
SELECT * FROM tblcities WHERE id IN (
SELECT city_id
FROM tblMembers
GROUP BY city_id
HAVING COUNT(*) = (
SELECT MAX(TOTAL)
FROM (
SELECT COUNT(*) AS TOTAL
FROM tblMembers
GROUP BY city_id
) AS AUX
)
)
That way, if there is a tie, still you'll get all cities with the maximum number of members...
Select ...
From tblCities As C
Join (
Select city_id, Count(*) As MemberCount
From tblMembers
Order By Count(*) Desc
Limit 1
) As MostMembers
On MostMembers.city_id = C.id
select top 1 c.id, c.name, count(*)
from tblcities c, tblmembers m
where c.id = m.city_id
group by c.id, c.name
order by count(*) desc