Question

Created table named geosalary with columns name, id, and salary:

name   id  salary  
patrik  2  1000  
frank   2  2000  
chinmon 3  1300  
paddy   3  1700  

I tried this below code to find 2nd highest salary:

SELECT salary
FROM (SELECT salary, DENSE_RANK() OVER(ORDER BY SALARY) AS DENSE_RANK FROM geosalary)
WHERE DENSE_RANK = 2;

However, getting this error message:

ERROR: subquery in FROM must have an alias  
SQL state: 42601  
Hint: For example, FROM (SELECT ...) [AS] foo.  
Character: 24  

What's wrong with my code?

Was it helpful?

Solution

I think the error message is pretty clear: your sub-select needs an alias.

SELECT t.salary 
FROM (
      SELECT salary,
          DENSE_RANK() OVER (ORDER BY SALARY DESC) AS DENSE_RANK 
      FROM geosalary
      ) as t  --- this alias is missing
WHERE t.dense_rank = 2

OTHER TIPS

The error message is pretty obvious: You need to supply an alias for the subquery.

Here is a simpler / faster alternative:

SELECT DISTINCT salary
FROM   geosalary
ORDER  BY salary DESC NULLS LAST
OFFSET 1
LIMIT  1;

This finds the "2nd highest salary" (1 row), as opposed to other queries that find all employees with the 2nd highest salary (1-n rows).

I added NULLS LAST, as NULL values typically shouldn't rank first for this purpose. See:

SELECT department_id, salary, RANK1 FROM (
    SELECT department_id,
           salary,
           DENSE_RANK ()
              OVER (PARTITION BY department_id ORDER BY SALARY DESC)
              AS rank1
    FROM employees) result  
WHERE rank1 = 3

This above query will get you the 3rd highest salary in the individual department. If you want regardless of the department, then just remove PARTITION BY department_id

Your SQL engine doesn't know the "salary" column of which table you are using, that's why you need to use an alias to differentiate the two columns. Try this:

SELECT salary
FROM (SELECT G.salary ,DENSE_RANK() OVER(ORDER BY G.SALARY) AS DENSE_RANK FROM geosalary G)
WHERE DENSE_RANK=2;
WITH salaries AS (SELECT salary, DENSE_RANK() OVER(ORDER BY SALARY) AS DENSE_RANK FROM geosalary)
SELECT * FROM salaries WHERE DENSE_RANK=2;
select  level, max(salary)
from   geosalary
where   level=2
connect  by
prior   salary>salary
group  by  level;

In case of duplicates in salary column below query will give the right result:

WITH tmp_tbl AS
  (SELECT salary,
    DENSE_RANK() OVER (ORDER BY SALARY) AS DENSE_RANK
  FROM geosalary
  )
SELECT salary
FROM tmp_tbl
WHERE dense_rank =
  (SELECT MAX(dense_rank)-1 FROM tmp_tbl
  )
AND rownum=1;

Here is SQL standard

SELECT name, salary
FROM   geosalary 
ORDER BY salary desc
OFFSET 1 ROW
FETCH FIRST 1 ROW ONLY

To calculate nth highest salary change offset value

SELECT MAX(salary) FROM geosalary WHERE salary < ( SELECT MAX(salary) FROM geosalary )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top