I'm trying to answer a SQL Leetcode question on Medium Difficulty. The question is asking me to find the people that have the highest salary per department.
I tried using GROUP BY but wasn't able to figure out that approach so I tried to use the PARTITION BY in order to find the max salary for each department. Afterwards, I would add a final WHERE statement where I could filter down to people with a salary that equals the max salary.
This is the query I have so far:
SELECT
Department.Name AS Department,
Employee.Name AS Employee,
Employee.Salary,
MAX(Employee.Salary) OVER (PARTITION BY Department.Name) AS MaxSalary
FROM Employee
LEFT JOIN Department ON Department.id = Employee.DepartmentId
;
There's two tables.
EMPLOYEE TABLE:
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+----+-------+--------+--------------+
DEPARTMENT TABLE:
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
and the correct output should look like this.
CORRECT EXPECTED OUTPUT:
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+
Running my current query leads to a runtime error with this message:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(PARTITION BY Department.Name) AS MaxSalary
FROM Employee
LEFT JOIN Department O' at line 7
I've looked over the syntax multiple times so I assume it's a incorrect understanding of how PARTITION BY works. I was expecting that I would see the max salary for each department listed on the right for each individual. Something like this:
+----+-------+--------+--------------+-----------+
| Id | Name | Salary | DepartmentId | MaxSalary |
+----+-------+--------+--------------+-----------+
| 1 | Joe | 70000 | 1 | 90000 |
| 2 | Jim | 90000 | 1 | 90000 |
| 3 | Henry | 80000 | 2 | 80000 |
| 4 | Sam | 60000 | 2 | 80000 |
| 5 | Max | 90000 | 1 | 90000 |
+----+-------+--------+--------------+ -----------+
After achieving that, I was going to add this line:
WHERE Employee.Salary = MaxSalary;
What is the proper way to do this?
You can consider using one of the following:
SELECT D.Name AS Department, E.Name AS Employee, E.Salary
FROM Employee AS E LEFT JOIN Department AS D ON E.DepartmentId = D.id
WHERE (E.Salary = (SELECT MAX(X.Salary) FROM Employee AS X WHERE (X.DepartmentId = E.DepartmentId)));
SELECT D.Name AS Department, E.Name AS Employee, E.Salary
FROM Employee AS E LEFT JOIN Department AS D ON E.DepartmentId = D.id
INNER JOIN (SELECT DepartmentId, MAX(Salary) AS MaxSalary FROM Employee GROUP BY DepartmentId) AS X ON E.DepartmentId = X.DepartmentId AND E.Salary = X.MaxSalary;
Related
I have a sample table below,
+-------------+-------------+-------------+----------+------------+---------------------------------+----------+---------------+
| employee_id | first_name | last_name | email | joined_date| title | salary | supervisor_id |
+-------------+-------------+-------------+----------+------------+---------------------------------+----------+---------------+
| 100 | John | King | EM1 | 1984-06-17 | CEO | 14000.00 | NULL |
| 101 | Leona | Kochhar | EM2 | 1993-09-21 | COO | 10000.00 | 100 |
| 102 | Lex | De Haan | EM3 | 1992-01-13 | CFO | 9000.00 | 100 |
| 103 | Alexander | Hunold | EM4 | 2001-04-03 | Gamer | 5000.00 | 102 |
| 104 | Dave | William | EM5 | 2002-05-21 | Gamer | 2000.00 | 103 |
| 105 | David | Austin | EM6 | 2002-06-25 | Gamer | 2800.00 | 103 |
| 106 | Valli | Longwind | EM7 | 2002-02-43 | Gamer | 2800.00 | 103 |
Certain employees are supervisors to other employees in this table. Do note that supervisor_id is the employee_id.
I am tasked to only use SELECT statement to get the employee_id, first_name, salary of the supervisors and the total number of employee under the supervisor.
In my mind, I know that I will need to use some sort of grouping and count. First, COUNT number of employees under each supervisor and second to GROUP BY supervisor ID. I managed to get the output using the simple COUNT and GROUP BY using this query:
SELECT employee_id, COUNT(supervisor_id)
FROM EMPLOYEE
GROUP BY supervisor_id;
This output the supervisor_id and number of employees under the supervisor_id. Which is:
+---------------+----------------------+
| supervisor_id | COUNT(supervisor_id) |
+---------------+----------------------+
| NULL | 0 |
| 100 | 2 |
| 101 | 0 |
| 102 | 0 |
| 103 | 3 |
*Table above slightly modified - this is a sample output
As mentioned, supervisor_id is the employee_id of the employee within the same table. My problem is that I am unable to get this table to display the employee_id, first_name and salary together with the COUNT column. The end result must show the employee_id (linked to supervisor_id), first_name, salary, COUNT.
I have tried this
SELECT employee_id, first_name, salary, COUNT(supervisor_id)
FROM EMPLOYEE
GROUP BY employee_id, first_name, salary, supervisor_id;
But this just returns the original table.
Also when I tried this
SELECT employee_id, first_name, salary, COUNT(supervisor_id)
FROM EMPLOYEE
GROUP BY supervisor_id;
It returns error "Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column" which according to online is how I craft my query (can't mix aggregated and non-aggregated column?).
Can anyone guide me on this? Thanks.
I guess you just need self LEFT JOIN here:
https://www.db-fiddle.com/f/miLeekBXxoiVV1SxuTYc2c/0
SELECT s.employee_id, s.first_name, s.last_name, s.salary, COUNT(e.employee_id)
FROM employee s
LEFT JOIN employee e
ON e.supervisor_id = s.employee_id
GROUP BY s.employee_id, s.first_name, s.last_name, s.salary;
By the way, you've mentioned in comment that you want to use HAVING COUNT() = 0. You should better not use HAVING for this purpose but just change this query to INNER JOIN. It will do the same but more efficient way.
https://www.db-fiddle.com/f/gM6q1UyagrZ4e1EHRvJ1NU/0
Please try this
SELECT E1.supervisor_id,count(E2.supervisor_id) FROM `EMPLOYEE` AS E1
LEFT JOIN (select supervisor_id FROM EMPLOYEE GROUP BY
supervisor_id) AS E2 ON E1.supervisor_id = E2.supervisor_id
GROUP BY E1.supervisor_id
I made this simple database on mysql and with data in my "Work" pivot table, I get the expected results with :
SELECT emp_name, dept_name
FROM Employee e
INNER JOIN Work w ON e.emp_id=w.emp_id
INNER JOIN Department d ON w.dept_id=d.dept_id;
+----------+-----------+
| emp_name | dept_name |
+----------+-----------+
| James | Sales |
| Jack | Marketing |
| James | Finance |
| Tom | Marketing |
+----------+-----------+
But now, if my pivot table is empty, I get NO RESULT as I would expect at least my emp_name list :
+----------+
| emp_name |
+----------+
| James |
| Jack |
| Henry |
| Tom |
+----------+
==> What should be the query for that ???
Thanks for help !
+--------+----------+--------+ Employee table
| emp_id | emp_name | salary |
+--------+----------+--------+
| 1 | James | 2000 |
| 2 | Jack | 4000 |
| 3 | Henry | 6000 |
| 4 | Tom | 8000 |
+--------+----------+--------+
+-------+-----------+ Department table
|dept_id| dept_name |
+-------+-----------+
| 1 | Sales |
| 2 | Marketing |
| 3 | Finance |
+-------+-----------+
+--------+---------+ Work table
| emp_id | dept_id |
+--------+---------+
| 1 | 1 |
| 2 | 2 |
| 1 | 3 |
| 4 | 2 |
+--------+---------+
Use a "left outer join":
SELECT emp_name, dept_name
FROM Employee e
LEFT JOIN Work w ON e.emp_id=w.emp_id
LEFT JOIN Department d ON w.dept_id=d.dept_id;
You seem to want left join:
SELECT emp_name, dept_name
FROM Employee e LEFT JOIN
Work w
ON e.emp_id = w.emp_id LEFT JOIN
Department d
ON w.dept_id = d.dept_id;
Note that this still returns two columns, but the second column is NULL.
In some situations, you need to fabricate a table for the columns.
I wanted a table with 24 columns, one per hour. In the output, I would put counts for actions grouped by day + hour. When there was no action in an hour, I wanted blank, not zero. (Blank stands out more than "0".)
To achieve that, I built a table with just 0..23.
SELECT ...
FROM seq_0_to_23 AS hours
LEFT JOIN the_data ON ...
I have two tables. Table of employees Employee and departments Department.
The Employee table looks like this:
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 85000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
| 5 | Janet | 69000 | 1 |
| 6 | Randy | 85000 | 1 |
| 7 | Will | 70000 | 1 |
+----+-------+--------+--------------+
The Department table looks like this:
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
I want to write a query that for each department will output employees and a number indicating the salary rating. (If the salary is the maximum in the department, the number is 1. If there are two identical salaries in the department, then their rating number must be the same).
I implemented this query using the window function ROW_NUMBER():
SELECT
d.Name Department,
e.Name Employee,
e.Salary,
ROW_NUMBER() OVER (
PARTITION BY d.Name
ORDER BY e.Salary DESC
) SalaryRating,
FROM
Employee e
LEFT JOIN Department d
ON e.DepartmentId = d.Id;
This query outputs the following data:
Department Employee Salary SalaryRating
IT Max 90000 1
IT Joe 85000 2
IT Randy 85000 3
IT Will 70000 4
IT Janet 69000 5
Sales Henry 80000 1
Sales Sam 60000 2
There is a mistake. Randy SalaryRating value is 3, but it should be 2, because he has the same salary as Joe.
What is the error in my query? How to fix it?
You can use DENSE_RANK
SELECT
d.Name Department,
e.Name Employee,
e.Salary,
DENSE_RANK() OVER (
PARTITION BY d.Name
ORDER BY e.Salary DESC
) SalaryRating,
FROM
Employee e
LEFT JOIN Department d
ON e.DepartmentId = d.Id;
I have a PostgreSQL database linked to a Drill instance.
Whenever I am trying to join 2 tables which both have a column name and whenever I want to select this name Drill selects the wrong name column. What am I doing wrong?
Given the following 2 tables:
Department
| id | name |
|----|------|
| 1 | A |
| 2 | B |
Employee
| id | name | dept | salary |
|----|------|------|--------|
| 1 | U | 1 | 100 |
| 2 | V | 1 | 75 |
| 3 | W | 1 | 120 |
| 4 | X | 2 | 95 |
| 5 | Y | 2 | 140 |
| 6 | Z | 2 | 55 |
Running
select employee.name, employee.salary
from employee
inner join department on employee.dept = department.id
where department.name = 'A'
returns
| name | salary |
|------|--------|
| A | 100 |
| A | 75 |
| A | 120 |
Running
select dept.name, employee.salary
from employee
inner join department on employee.dept = department.id
where department.name = 'A'
returns
| name | salary |
|------|--------|
| null | 100 |
| null | 75 |
| null | 120 |
What does work, but seems very silly to me, is:
select dept.name, employee.salary
from employee
inner join (select id, name as deptname from department) as department on employee.dept = department.id
where department.deptname = 'A'
This seems to be because you use
select dept.name, [...]
But you have never assigned an alias for the table department (department AS dept). Hence
select department.name, [...]
should yield the value you are looking for.
I Have a table called EMPLOYEE
| employee_id | name | supervisor_id |
| 123 | Ace Ven | NULL |
| 124 | Ben Agent | 123 |
| 125 | Sam Marks | 123 |
| 126 | Bob Teabag | 125 |
| 127 | Matthew Smith | 125 |
| 128 | Toby McQuire | 123 |
I am trying to find the supervisors and list the amount of employees they have. as you can see the supervisor_id is the same as employee_id. Should come out like this
name | total_employees |
Ace Ven | 3 |
Sam Marks | 2 |
I tried
SELECT supervisor_id, name, count(supervisor_id) AS total_employees FROM EMPLOYEE GROUP BY name HAVING (total_employees > 0);
which didn't work at all (sorry about the format, can't seem to get it to work).
Subquery counts how many records/employees are for each supervisor_id, then this result simply joined table again for retrieving their names:
select your_table.name, t.total_employees from your_table
inner join
(select supervisor_id, count(*) as total_employees from your_table where supervisor_id is not null group by supervisor_id) t
on your_table.employee_id = t.supervisor_id
A simple join will suffice...
Select x.name
, count(*) total
from employee x
join employee y
on y.supervisor_id = x.employee_id
group
by x.employee_id;