How do I select top rows in SQL - sql

I have a code that outputs Department Names and their number of workers.
SELECT department_name,COUNT (employee_id) FROM EMPLOYEES
JOIN DEPARTMENTS
ON employees.department_id=departments.department_id
GROUP BY department_name
ORDER BY count(employee_id) DESC
I want to select the first three department names that have the largest number of workers. . When I WHERE, I get three rows, but the output is not true.
SELECT department_name,COUNT (employee_id) FROM EMPLOYEES
JOIN DEPARTMENTS
ON employees.department_id=departments.department_id
WHERE rownum <= 4
GROUP BY department_name
ORDER BY count(employee_id) DESC
What can you recommend to me about this issue? Also, I will use this query in a PL/SQL block.
THANKS!

That rownum clause happens before the sort. You can either use
fetch first 3 rows only
after the order by clause, if using Oracle 12c or above, or with rownum use a subquery -
select * from (
your query here
)
where rownum < 4;

Related

Optimizing query with subselect in two tables

Table employee has two columns:
ID
NAME
Table external_job also has two columns:
ID
SALARY
I have to get one person who got the maximum salary.
The result must have three columns and one row:
ID
NAME
SALARY
I made a query but the client asked me not to use a sub-select query.
How can I do in this case?
My query is:
select *
from (select a.id,
a.name,
(select sum(salary)
from external_job b
where b.id = a.id) salary
from employee a
order by salary desc)
where rownum = 1
Use order by and some method for limiting the results to one row. In standard SQL this is:
select ej.id, e.name, ej.salary
from employee e join
external_job ej
on ej.id = e.id
order by ej.salary
fetch first 1 row only;
Not all databases support fetch first. Some use limit or select top or even more arcane constructs.
Assumption is ID is primary key on both sides.
select ID, NAME, SALARY from employee e , external_job a where e.id= a.id
order by salary desc
limit 1

Oracle WHERE Clause/Searching

I'm a beginner to oracle. In recent search I've seen WHERE N-1,3-2 ..so on.
How does it work in searching data?
This is my code attemtp so far:
SELECT name, salary
FROM #Employee e1
WHERE N-1 = (SELECT COUNT(DISTINCT salary) FROM #Employee e2
WHERE e2.salary > e1.salary)
It's a classic( and pretty old ) SQL query to get nth highest salary. I assume It is no longer used( I haven't seen ) in any production codes, but could be a favourite question among the interviewers.
The N you are referring to is not a column or some unknown entity but a placeholder which should translate to a valid integer or bind argument in the working query. It is a correlated subquery, a subquery that is evaluated once for each row processed by the outer query. The way it works is that it takes a count of distinct list of salary values from employees that have a salary greater than each one of employees coming from the outer query and restricts the result where that count is equal to N-1.Which means you get those rows with nth highest salaries.
A more commonly used way to do this would be to use analytic function dense_rank() ( or rank depending on your need ). Read the documentation for these functions in case you aren't aware of them.
SELECT first_name,
salary
FROM (
SELECT e.*,
dense_rank() OVER(
ORDER BY salary desc
) rn
FROM employees e
)
WHERE rn = 6; -- ( n = 6 )
In Oracle 12c and higher versions, even though the above query works, a handy option to use is the FETCH..FIRST syntax.
SELECT *
FROM employees
ORDER BY salary DESC OFFSET 6 ROWS FETCH FIRST 1 ROWS WITH TIES; --n=6

ORACLE 12C - SELECT query using ROWNUM

I have to get second five (6-10) best salaries records from sorted table using ROWNUM.
Using ROWNUM is necessary.
When I execute query:
SELECT ROWNUM AS position, name, salary
FROM (SELECT name, salary
FROM employees
ORDER BY salary DESC)
WHERE ROWNUM <= 10;
I get a first 10 best records.
And now when I try execute query:
SELECT ROWNUM AS position, name, salary
FROM (SELECT name, salary
FROM employees
ORDER BY salary DESC)
WHERE ROWNUM >= 6 AND ROWNUM <= 10;
I get a empty table. Why doesn't it work?
As explained in the documentation, rownum is evaluated as the rows are fetched. If you never fetch the first row, you never get to the second. Hence, no rows are fetched:
Conditions testing for ROWNUM values greater than a positive integer
are always false. For example, this query returns no rows:
SELECT * FROM employees
WHERE ROWNUM > 1;
But, more importantly, you are using Oracle 12C. So, use fetch first instead of rownum. This has multiple advantages. Besides being standard SQL, you don't need a subquery:
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;
And for your second:
SELECT name, salary
FROM employees
ORDER BY salary DESC
OFFSET 5 ROWS
FETCH FIRST 5 ROWS ONLY;
I write in queston that using ROWNUM is necessary, because it's
academic task.
In such a case use a subquery
SELECT name, salary
FROM (
SELECT name, salary, ROWNUM as my_rownum
FROM employees
ORDER BY salary DESC
)
WHERE my_rownum BETWEEN 6 AND 10
You can use below query and try....
SELECT name,salary from
( SELECT name,salary, DENSE_RANK() OVER (ORDER BY salary DESC) as rn
from employees )
where rn between 6 and 10;

sql query to fetch top 3 salaries

emp_name |salary
---------------
A |12568
B |3000
C |7852
D |2568
E |9852
F |1598
G |8569
I want a sql query to fetch the lowest 3 salaried employees
If you are using Oracle 12c or later you can make your query simpler with fetch. Instead of writing inner queries like this.
SELECT *
FROM
(SELECT * FROM EMPLOYEES EMP ORDER BY EMP.SALARY ASC
)
WHERE ROWNNUM <= 3
You can combine them into a single query.
SELECT * FROM employees emp ORDER BY emp.salary ASC
FETCH FIRST 3 ROWS ONLY;
More Information on the syntax and construct is available here.
http://www.dba-oracle.com/t_offset_fet_first_rows_only.htm
ORACLE:
SELECT emp_name
FROM ( SELECT *
FROM employees e
ORDER BY e.salary ASC)
WHERE ROWNUM < 4
Good luck!
You can use top 3 to get three record after ordering them in descending or ascending order. I have SQL server syntax but you can have idea from this for you target DBMS.
For top three max salaries
Select top 3 emp_name, salary
order by salary desc
For top three minimum salaries
Select top 3 emp_name, salary
order by salary asc
USE ASC AND LIMIT
Select emp_name, salary FROM TABLE_NAME
order by salary ASC LIMIT 3;
You didn't specify your DBMS, so this is ANSI SQL:
select emp_name, salary
from (
select emp_name, salary,
dense_rank() over (order by salary) as rnk
from employees
) t
where rnk <= 3;
This will also deal with employees that have the same salary. So the result might be more then three rows if more then one of the employees with the lowest salary have the same salary.

What kind of query is this?

In my Employee table, I wanted to find the 3rd highest salary. Someone provided me with the following query to do this:
SELECT *
FROM employee C1
WHERE 3 = (SELECT Count(DISTINCT( C2.salary ))
FROM employee C2
WHERE C2.salary >= C1.salary)
This query works, but I don't how it works. What kind of query is this?
As others have said, this type of query is called a correlated sub-query. It's a sub-query because there is a query within a query and it's correlated because the inner query references the outer query in its definition.
Consider the inner query:
SELECT Count(DISTINCT( C2.salary ))
FROM employee C2
WHERE C2.salary >= C1.salary
Conceptually, this inner query will be evaluated once for every row produced by the outer query before the WHERE clause is applied, basically once for every row in employee. It will produce a single value, the count of rows from employee where the salary is less than the salary of the outer row.
The outer query will only return records where the value produced by the inner query is exactly 3. Assuming unique salary values, there is only one row from the employee table where there will be exactly 3 records with a salary value greater than or equal to it (the one row) and that one row is necessarily the third-highest salary value.
It's clever, but unnecessarily weird and probably not as optimal as something more straightforward.
Maybe a better solution would have been
SELECT TOP 1 *
FROM (
SELECT TOP 3 * FROM employee ORDER BY Salary DESC
) t
ORDER BY Salary ASC
Easier to read and more efficient than a correlated sub-query.
You can also use Dense_Rank to rank the salaries greatest to least, then select the ones that are ranked 3rd. This will also prevent you from getting the wrong salary if the top 2 are identical like the other answers above mine are doing. This has a better looking execution plan than the Distinct count one also
SELECT *
FROM (
SELECT *,
DENSE_RANK() OVER (ORDER BY Salary DESC) salary_rank
FROM employee e
) t
WHERE salary_rank = 3
Could also rewrite this with a common table expression.
WITH top_three
AS
(
SELECT TOP 3 * FROM employee ORDER BY Salary DESC
)
SELECT TOP 1 *
FROM top_three
ORDER BY Salary ASC;
Or, if you need to look for other ranks in this you can use row_number().
WITH ranked
AS
(
SELECT rank = ROW_NUMBER()OVER(ORDER BY Salary DESC), *
FROM employee
ORDER BY Salary DESC
)
SELECT *
FROM ranked
WHERE rank = #whatever_rank_you_want;