SQL query with Highest value with tie - mysql

I am trying to write a query that lists students who have earned the highest total credit in each department. I have to also include tied students in the result.
The query should return relation with department name, student name and total credit they earned.
SELECT s.dept_name, s.name, s.max
FROM (SELECT dept_name, name, MAX(tot_cred) as max
FROM university.student GROUP BY dept_name) as s,
university.student as t
WHERE s.name = t.name;
It is giving errors and I don't know how to deal with ties.
If I delete the name part in the query, I have managed to get the highest credits in each department(without a tie)
The table student consists of an ID, name, department, total credit.

Use RANK() window function:
SELECT t.dept_name, t.name, t.tot_cred
FROM (
SELECT dept_name, name, tot_cred,
RANK() OVER(PARTITION BY dept_name ORDER BY tot_cred DESC) rn
FROM university.student
) t
WHERE t.rn = 1
This is an alternative in case you can't use window functions:
SELECT s.dept_name, s.name, s.tot_cred
FROM university.student s
INNER JOIN (
SELECT dept_name, MAX(tot_cred) tot_cred
FROM university.student
GROUP BY dept_name
) t ON t.dept_name = s.dept_name AND s.tot_cred = t.tot_cred
or with NOT EXISTS:
SELECT s.dept_name, s.name, s.tot_cred
FROM university.student s
WHERE NOT EXISTS (
SELECT 1 FROM university.student
WHERE dept_name = s.dept_name AND tot_cred > s.tot_cred
)

Related

Why this code showing invalid use of group function?

CREATE VIEW SALESMAN_WITH_MAX_ORDER AS
(SELECT S.Salesman_id,
S.Name,
S.City,
Commission
FROM SALESMAN S,
CUSTOMER C
WHERE S.Salesman_id=C.Salesman_id
AND Customer_id IN (SELECT Customer_id
FROM ORDERS
GROUP BY Customer_id,
Ord_Date
HAVING SUM(PURCHASE_AMT) = (SELECT MAX(SUM(PURCHASE_AMT))
FROM ORDERS
GROUP BY Customer_id,
Ord_Date)));
You have a problem in the innermost query. You cannot do a MAX with a SUM as argument.
This is how you would do it in T-SQL, sorry I have no mysql to test it on right now.
CREATE VIEW SALESMAN_WITH_MAX_ORDER AS
(
SELECT S.Salesman_id,
S.Name,
S.City,
Commission
FROM SALESMAN S,
CUSTOMER C
WHERE S.Salesman_id=C.Salesman_id
AND Customer_id IN
(
SELECT Customer_id
FROM ORDERS
GROUP BY Customer_id,Ord_Date
HAVING SUM(PURCHASE_AMT)=
(
SELECT MAX(SUM_AMT)
FROM
(
SELECT SUM(PURCHASE_AMT) AS SUM_AMT
FROM ORDERS
GROUP BY Customer_id,Ord_Date
) innerTableName
)
)
);

SELECT MAX(COUNT) MySQL

I am new to MySQL, and I have a task to do right now where I have three tables:
students(id,name)
courses(id,name)
grades(id, student_id (FK), course_id(FK), grade)
I am supposed to
fetch the name of the course that is the most registered by students and if there is any conflict or ties with other course, retrieve the course after sorting ascendingly.
I tried several queries, but they are not 'efficient enough'
SELECT course.name FROM (
SELECT CI ,MAX(Total) FROM
(
SELECT course_id as CI,COUNT(*) AS Total
FROM grades
GROUP BY course_id ASC
) AS Results
) AS x
INNER JOIN courses ON x.CI = courses.id
And
SELECT courses.name FROM (
SELECT course_id, COUNT(*) AS how_many
FROM grades
GROUP BY course_id ASC
HAVING how_many = (
SELECT COUNT(*) AS how_many
FROM grades
GROUP BY course_id
ORDER BY how_many DESC
LIMIT 1
)
LIMIT 1
) AS X
JOIN courses ON X.course_id=courses.id
Is there any more efficient query?
Both your query attempts look logically incorrect to me. You should be joining courses to grades to obtain the number of students enrolled in each course. Regarding efficiency, the RANK analytic function is one of the most performant options, assuming you are running MySQL 8+:
WITH cte AS (
SELECT c.id, c.name, RANK() OVER (ORDER BY COUNT(*) DESC, c.name) rnk
FROM courses c
INNER JOIN grades g ON g.course_id = c.id
GROUP BY c.id, c.name
)
SELECT id, name
FROM cte
WHERE rnk = 1;
On earlier versions of MySQL, we can use a LIMIT query:
SELECT c.id, c.name
FROM courses c
INNER JOIN grades g ON g.course_id = c.id
GROUP BY c.id, c.name
ORDER BY COUNT(*) DESC, c.name
LIMIT 1;
You can use the ORDER BY clause with the LIMIT clause to get what you need, without aggregating twice:
WITH enrollments AS (
SELECT course_id, COUNT(DISTINCT student_id) AS num_enrollments
FROM grades
GROUP BY course_id
)
SELECT *
FROM enrollments e
INNER JOIN courses c
ON e.course_id = c.id
ORDER BY e.num_enrollments DESC, c.name ASC
LIMIT 1
The subquery will get you the enrollments by aggregating on the students,
then it is joined with the courses to use the course name.
Data is then ordered by:
number of enrollments descendent
course name ascendent
and only the first row is considered.

How to display project, group members and their boss side by side in mySQL

I want to show (team id, team name, intern id, intern name, reporter id, reporter name) for all my records. I don't know how to separate interns in one column and reporters in another for same team. I want to do this because I want each reporter to provide evaluation for each intern they are working with in that group.
You could use a join with sub query for Intern and Reporter
select a.teamID, a.temaName,
b.peopleID intren_id, b.firstname intern_name, b.lastname inter_lastname,
c.peopleId, c.firstname reporter_name, c.lastname reporter_lastname
from mytable a
inner join (
select teamId, firstname, lastname
from mytable
where pType = 'Intern'
) b on a.teamId = b.teamId
inner join (
select teamId, firstname, lastname
from mytable
where pType = 'Reporter'
) c on a.teamId = c.teamId
I think you want columns that are vertical "lists". This is not really a relational structure, because the values in the rows don't relate to each other.
However, you can do it using conditional aggregation. However, you need to enumerate the values. In MySQL 8+, this is easy using row_number(), so the query looks like:
select teamid, teamname,
max(case when ptype = 'intern' then peopleid end) as intern,
max(case when ptype = 'reporter' then peopleid end) as reporter
from (select t.*,
row_number() over (partition by teamid, ptype order personid) as seqnum
from t
) t
group by teamid, teamname, seqnum;

Fetch only the department that has the highest number of employees

I have 2 tables in my database.
Table 1. employee
id
name
department_id
Table 2. department
id
name
What will be the query to fetch all employees with their department?
So I have written this query
SELECT employee.name
, department.name
FROM employee
JOIN department
ON employee.department_id = department.id
And this seems to be correct but I am not able to write a query if I want to fetch only the department that has the highest number of employees. How can I achieve this?
To guarantee just one department...
SELECT
*
FROM
department
WHERE
id = (SELECT department_id
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
Note, if two departments are tied with joint maximum employees, this will still only select One of them (arbitrarily chosen, potentially different each time).
To handle ties, you could do the following...
SELECT *
FROM department
WHERE id IN (SELECT department_id
FROM employee
GROUP BY department_id
HAVING COUNT(*) = (SELECT COUNT(*)
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
)
This is a real pain to handle in MySQL. Here is one option:
SELECT d1.id, d1.name
FROM department d1
INNER JOIN employee e1
ON d1.id = e1.department_id
GROUP BY d1.id, d1.name
HAVING COUNT(*) = (SELECT COUNT(*) FROM department d2 INNER JOIN employee e2
ON d2.id = e2.department_id
GROUP BY d2.id ORDER BY COUNT(*) DESC LIMIT 1);
Note that if you were using a database with analytic function support, such as SQL Server, then the problem gets much easier:
SELECT id, name
FROM
(
SELECT d.id, d.name, DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) dr
FROM department d
INNER JOIN employee e
ON d.id = e.department_id
GROUP BY d.id, d.name
) t
WHERE t.dr = 1;
This question can be solved in multiple ways:
Using sub query
SELECT name FROM department
WHERE id IN
(SELECT department_id FROM employee HAVING COUNT(department_id)
IN
(SELECT MAX(COUNT(department_id)) FROM employee) GROUP BY department_id)
Using Join
SELECT name FROM employee e
INNER JOIN
department d ON e.department_id = d.id
HAVING COUNT(e.department_id)
IN
(SELECT MAX(COUNT(department_id)) from employee) group by department_id)
first check the column related two types have same name, same data type and the use subquery
SELECT name
FROM department
WHERE id IN (
SELECT department_id
FROM employees
HAVING COUNT(department_id) IN (
SELECT MAX(COUNT(dept_id))
FROM employees
)
GROUP BY department_id
)
Your query should work for the first question.
for the second, You can use this. The sub query would give you the dept Id for the most employees, which the outer query would give additional details for.
select * from department where department_id in
(select limit 1 Employee.department_id from Employee group by department_id
order by count(Employee.name) desc)

select department(s) with maximum number of employees

I have two tables EMP(id,name,DEPT_id) and DEPT(id ,name). I need to find the department(s) in which the maximum number of employees work. Please help.
This will give the department name of the department which is having maximum number of employees.
Select DEPT_NAME from department where DEPT_ID = (select DEPT_ID from (Select DEPT_ID, count(DEPT_ID) from Employee group by DEPT_ID order by count(DEPT_ID) desc) where rownum = 1);
Just a little more verbose than the other two solutions, but it will get the job done...feel free to tweak to your convenience.
select countbydept.*
from
(
-- from EMP table, let's count number of records per dept
-- and then sort it by count (highest to lowest)
-- and take just the first value. We just care about the highest
-- count
select dept_id, count(*) as counter
from emp
group by dept_id
order by counter desc
limit 1
) as maxcount
inner join
(
-- let's repeat the exercise, but this time let's join
-- EMP and DEPT tables to get a full list of dept and
-- employe count
select
dept.id,
dept.`name`,
count(*) as numberofemployees
from dept
inner join emp on emp.dept_id = dept.id
group by dept.id, dept.`name`
) countbydept
-- combine the two queries's results by matching the employee count
on countbydept.numberofemployees = maxcount.counter
Example: http://sqlfiddle.com/#!9/7d6a2d/1
Try this query.
SELECT a.name,Max(a.NumEmp) AS maxEmpCount FROM ( SELECT d.name,COUNT(*) AS NumEmp FROM EMP e INNER JOIN DEPT d ON e.DEPT_id = d.id GROUP BY e.DEPT_id ) AS a GROUP BY a.name
you can solve this using with statement like this:
with deps as
(select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name)
select deps.dep_name,cnt from deps
where cnt=(select max(cnt) from deps)
OR
select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name
having count(emp.employee_id) >= all (select count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id =
dep.department_id
group by dep.department_name)
OR
with s1 as
(select dep.department_name as dep_name,
count(emp.employee_id) over(partition by dep.department_name) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
order by cnt desc),
s2 as
(select s1.dep_name,
s1.cnt,
row_number() over(order by cnt desc) as row_num
from s1)
select dep_name from s2 where row_num = 1
these solutions are proper for databases like Oracle that we do not have top(1) or limit 1
select Top 1 d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
order by counts desc
Or
select d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
having count(e.ename) = (select max(micount) from (select count(deptno) micount from emp group by DEPTNO) a)
You can try this query.
Select Id, Name from Dept
Where Id = (Select Top(1) DeptId from Emp
Group By DeptId
order by Count(DeptId) desc)
you can create view to find it.
CREATE VIEW TEMP AS SELECT COUNT(EMP.id) AS A, DEPT.name AS B
FROM EMP JOIN DEPT ON EMP.DEPT_id=DEPT.id GROUP BY DEPT.id;
SELECT MAX(A) FROM TEMP;
Now, EMP(id,name,DEPT_id) and DEPT(id ,name) these two tables are given. Now, I insert some entries in the table in such a manner that:
SELECT COUNT(*) AS NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
ORDER BY NO_OF_EMPLOYEES;
This query generates the following:
NO_OF_EMPLOYEES DEPT_NAME
3 Research
3 Finance
4 Sales
4 Product
Now, the query which gives the correct result:
SELECT COUNT(*) AS MAX_NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
HAVING MAX_NO_OF_EMPLOYEES=(
SELECT COUNT(*) AS NO_OF_EMPLOYEES
FROM EMP
GROUP BY DEPT_ID
ORDER BY NO_OF_EMPLOYEES DESC
LIMIT 1
);
It will generate:
MAX_NO_OF_EMPLOYEES DEPT_NAME
4 Sales
4 Product
This question can be solved in multiple ways
Using sub query
SELECT name FROM dept WHERE id IN (SELECT dept_id FROM emp HAVING COUNT(dept_id) IN (SELECT MAX(COUNT(dept_id)) FROM emp) GROUP BY dept_id)
Using Join
SELECT name FROM emp e INNER JOIN dept d ON e. dept_id = d. id HAVING COUNT(e.dept_id) IN (SELECT MAX(COUNT(dept_id)) from emp) group by dept_id)
If you have only emp table then below query will hep you get a results -
select a.* from (select deptno, dense_rank() over(order by count(*) desc ) as rank from dbo.emp group by deptno) a where a.rank =1
select deptno,count(*)from emp group by
deptno having count(*)=(select max(count(*))from emp group by deptno);
SELECT department_id, count(employee_id) as 'No_of_Emp'
FROM employees
GROUP BY department_id
ORDER BY No_of_Emp DESC