I have a table with 3 columns:
Name department salary
How can I determine using one query to find 3rd highest salary in each department?
One way is to LIMIT a correlated subquery, but it's not especially efficient:
SELECT department, (
SELECT salary
FROM my_table t2
WHERE t2.department = t1.department
ORDER BY salary DESC
LIMIT 2, 1
)
FROM my_table t1
GROUP BY department
In addition to eggyal's excellent answer, here's a query that will give you the names, too, of those that have salary equal to the third (in each department):
SELECT
t.name, t.department, t.salary AS third_salary
FROM
( SELECT DISTINCT department
FROM tableX
) AS d
JOIN
tableX AS t
ON t.department = d.department
AND t.salary =
( SELECT tt.salary -- notice that this
FROM tableX AS tt -- subquery is
WHERE tt.department = d.department -- exactly the same as
ORDER BY tt.salary DESC -- the one in
LIMIT 1 OFFSET 2 -- #eggyal's answer
) ;
This RANK question is similar to this one:
MySQL, Get users rank
I you can thy this:
SELECT s.*,
(
SELECT COUNT(*)
FROM salaries si
WHERE si.salary >= s.salary AND si.department = s.department
) AS rank
FROM salaries s
WHERE s.rank = 3
Try this:
SELECT name, department, salary
FROM (SELECT name, department, salary, IF(#dept=(#dept:=department), #auto:=#auto+1, #auto:=1) indx
FROM employee e, (SELECT #dept:=0, #auto:=1) A
ORDER BY department, salary DESC ) AS A
WHERE indx = 3;
Related
Any thoughts on why the following doesn't work.
The Table is called Incomes, it has 3 cols called, name, dept and salary. I want to get the name and salary of personnel in the marketing dept whose salary is less than the average salary of all employees.
When I run the following I get ERROR 1111.
SELECT name, salary
FROM income
WHERE dept = "marketing"
HAVING salary < AVG(salary)
You must use a subquery in the WHERE clause that returns the average:
SELECT name, salary
FROM income
WHERE dept = 'marketing'
AND salary < (SELECT AVG(salary) FROM income WHERE dept = 'marketing')
If by all employees you mean the average salary of employees of all departments, then remove WHERE dept = 'marketing' from the subquery.
As an alternative to putting the subquery in the WHERE clause, we could use an inline view:
SELECT t.name
, t.salary
FROM ( SELECT AVG(d.salary) AS avg_salary
FROM income d
WHERE d.dept = 'marketing'
) a
JOIN income t
ON t.salary > a.avg_salary
AND t.dept = 'marketing'
With the inline view, we can also return the average salary, and we can calculate the difference, even a percentage difference, for multiple departments
Expanding on the query a bit, something like this:
SELECT a.dept
, t.name
, t.salary
, a.avg_salary
, ((t.salary - a.avg_salary) / a.avg_salary) * 100.0 AS pct_greater
FROM ( SELECT d.dept
, AVG(d.salary) AS avg_salary
FROM income d
GROUP
BY d.dept
) a
JOIN income t
AND t.dept = a.dept
ON t.salary > a.avg_salary
ORDER
BY a.dept
, t.salary DESC
I have a salary table in which I am trying to return determine the lowest salary earned and by which industry for each year however despite getting the correct lowest salary earned I am receiving the wrong industry name.
I am aware that it is due to the fact that I have utilized GROUP BY without placing a constraint(?) on it hence it is returning me the wrong value but I am not sure how I can solve it.
SALARY TABLE
salaryID
salaryAmount
salaryYear
industryName (ForeignKey)
Can someone please guide me on the right path?
**(Problem Code)**
SELECT MIN(S.salary), S.industryName, S.salaryYear
FROM salary
GROUP BY S.salaryYear;
**(Attempted solution)**
SELECT S.salary
FROM salary
INNER JOIN
SELECT (min(S1.amount)), S1.year, S1.industryName, S1.salaryId
FROM salary S1
GROUP BY S1.year
ON S.salaryId = S1.salaryId);
Use a proper GROUP BY. Any non-aggregated columns must be included in GROUP BY.
SELECT MIN(amount), year
FROM salary
GROUP BY year
If you want to include industryName,
SELECT amount, year, industryName, salaryId
FROM (
SELECT amount, year, industryName, salaryId
, ROW_NUMBER() OVER(PARTITION BY year ORDER BY amount) AS rn
FROM salary
) a
WHERE rn = 1
Pre-MySQL 8 version
SELECT *
FROM salary s
INNER JOIN (
SELECT MIN(amount) AS minAmount, year
FROM salary
GROUP BY year
) m ON m.minAmount = s.amount AND m.year = s.year
I think you need a self-join :
SELECT s1.industryName, s2.min_salary, s2.salaryYear
FROM salary s1
JOIN
(
SELECT MIN(salary) as min_salary, salaryYear
FROM salary
GROUP BY salaryYear
) s2
ON s1.salary = s2.min_salary
AND s1.salaryYear = s2.salaryYear;
The Demo of this query with your sample data
I want to find name of that persons who worked most in a month. but the query doesn't returning max value from sum of value
I'm new in mysql
SELECT
x.name,
sec_to_time(MAX(x.sum_time)) maximum
FROM (
SELECT
name,
SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id = employees.id
AND project_id IS NOT NULL
GROUP BY employees_id
) x
GROUP BY x.name;
this is my query. i want to show just name of that persons who worked most in a month. but it returns all persons who worked in a month
Try making these changes to your query:
change name to MAX(name)
qualify employees_id with wh.employees_id
SELECT
x.name,
sec_to_time(MAX(x.sum_time)) maximum
FROM (
SELECT
MAX(name) AS name,
SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id = employees.id
AND project_id IS NOT NULL
GROUP BY wh.employees_id
) x
group by x.name;
Simply use Order by LIMIT -
SELECT X1.name, X1.maximum
FROM (SELECT name, SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) maximum
FROM working_hours wh, employees
WHERE wh.employees_id=employees.id
GROUP BY name) X1
JOIN (SELECT SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id=employees.id
AND project_id is not null
GROUP BY employees_id
ORDER BY sum_time DESC
LIMIT 1) X2 ON X2.sum_time = X1.maximum;
How to find the row with 7th highest salary from employee table in MySQL?
I have tried it this way but unable to get the exact query.
SELECT MAX(salary) FROM employee
WHERE salary NOT IN
(SELECT MAX(salary) FROM employee)
What a brief post!!! Try this though,
select *
from(
select distinct salary
from employee
order by salary desc limit 7
) t
order by salary
limit 1
maybe you can use this
SELECT * FROM employe ORDER BY salary DESC LIMIT 7
hope this will help you
I got the answer.
SELECT *
FROM one one1
WHERE ( 7 ) = ( SELECT COUNT( one2.salary )
FROM one one2
WHERE one2.salary >= one1.salary
)
SELECT *
FROM employees emp
WHERE 7 =
(SELECT COUNT(DISTINCT salary)
FROM employees
WHERE emp.salary<=salary );
**castID**
nm0000116
nm0000116
nm0000116
nm0000116
nm0000116
nm0634240
nm0634240
nm0798899
This is my table (created as a view). Now I want to list the castID which has the most count (in this case which is nm0000116, and how many occurences/count it has in this table ( should be 5 times) and I'm not quite sure which query to use
try
Select CastId, count(*) countOfCastId
From table
Group By CastId
Having count(*)
= (Select Max(cnt)
From (Select count(*) cnt
From table
Group By CastId) z)
SELECT
MAX(E),
castId
FROM
(SELECT COUNT(castId) AS E,castId FROM [directors winning movies list] GROUP BY castId) AS t
You could just return the topmost count using LIMIT:
SELECT castID,
COUNT(*) AS Cnt
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
LIMIT 1
;
However, if there can be ties, the above query would return only one row. If you want all the "winners", you could take the count from the above query as a scalar result and compare it against all the counts to return only those that match:
SELECT castID,
COUNT(*) AS Cnt
FROM atable
GROUP BY castID
HAVING COUNT(*) = (
SELECT COUNT(*)
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
LIMIT 1
)
;
(Basically, same as Charles Bretana's approach, it just derives the top count differently.)
Alternatively, you could use a variable to rank all the counts and then return only those that have the ranking of 1:
SELECT castID,
Cnt
FROM (
SELECT castID,
COUNT(*) AS Cnt,
#r := IFNULL(#r, 0) + 1 AS r
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
) AS s
WHERE r = 1
;
Please note that with the above method the variable must either not exist or be pre-initialised with a 0 or NULL prior to running the query. To be on the safe side, you could initialise the variable directly in your query:
SELECT s.castID,
s.Cnt
FROM (SELECT #r := 0) AS x
CROSS JOIN
(
SELECT castID,
COUNT(*) AS Cnt,
#r := #r + 1 AS r
FROM atable
GROUP BY castID
ORDER BY Cnt DESC
) AS s
WHERE s.r = 1
;