How to find nth highest or top n rows from a table
The question has two type of solution if we do not use the rowid or top operator.
One is with correlated sub query -
select distinct a.salary from example.employee a where 3 >= (select count(distinct salary) from example.employee b where a.salary <= b.salary) order by a.salary desc;
Since correlated sub query performed poorly since for every row of outer query the inner query executes once.
The better solution can be by querying using joins.
select distinct a.salary from example.employee a inner join example.employee b on a.salary<=b.salary group by a.salary having count(a.salary)<= 3 order by a.salary desc
Difference between IN and EXISTS clause in SQL
In many cases IN and EXISTS return the same result though there is a difference between them
When you write a query using the IN clause, you're telling the rule-based optimizer that you want the inner query to drive the outer query (think: IN = inside to outside). For example, to query the 14-row EMP table for the direct reports to the employee KING, you could write the following:
select ename from emp e
where mgr in (select empno from emp where ename = 'KING');
Here's the EXPLAIN PLAN for this query: where mgr in (select empno from emp where ename = 'KING');
OBJECT OPERATION
---------- ----------------------------------------
SELECT STATEMENT()
NESTED LOOPS()
EMP TABLE ACCESS(FULL)
EMP TABLE ACCESS(BY INDEX ROWID)
PK_EMP INDEX(UNIQUE SCAN)
This query is virtually equivalent to this: ---------- ----------------------------------------
SELECT STATEMENT()
NESTED LOOPS()
EMP TABLE ACCESS(FULL)
EMP TABLE ACCESS(BY INDEX ROWID)
PK_EMP INDEX(UNIQUE SCAN)
select e1.ename from emp e1,(select empno from emp where ename = 'KING') e2
where e1.mgr = e2.empno;
You can write the same query using EXISTS by moving the outer query column to a subquery condition, like this: where e1.mgr = e2.empno;
select ename from emp e
where exists (select 0 from emp where e.mgr = empno and ename = 'KING');
When
you write EXISTS in a where clause, you're telling the optimizer that
you want the outer query to be run first, using each value to fetch a
value from the inner query (think: EXISTS = outside to inside). where exists (select 0 from emp where e.mgr = empno and ename = 'KING');
The EXPLAIN PLAN result for the query is:
OBJECT OPERATION
---------- ----------------------------------------
SELECT STATEMENT()
FILTER()
EMP TABLE ACCESS(FULL)
EMP TABLE ACCESS(BY INDEX ROWID)
PK_EMP INDEX(UNIQUE SCAN)
This is virtually similar to the PL/SQL code: ---------- ----------------------------------------
SELECT STATEMENT()
FILTER()
EMP TABLE ACCESS(FULL)
EMP TABLE ACCESS(BY INDEX ROWID)
PK_EMP INDEX(UNIQUE SCAN)
set serveroutput on;
declare
l_count integer;
begin
for e in (select mgr,ename from emp) loop
select count(*) into l_count from emp
where e.mgr = empno and ename = 'KING';
if l_count != 0 then
dbms_output.put_line(e.ename);
end if;
end loop;
end;
To
determine which clause offers better performance in rule-based
optimization, consider how many rows the inner query will return in
comparison to the outer query. In many cases, EXISTS is better because
it requires you to specify a join condition, which can invoke an INDEX
scan. However, IN is often better if the results of the subquery are
very small. You usually want to run the query that returns the smaller
set of results first. declare
l_count integer;
begin
for e in (select mgr,ename from emp) loop
select count(*) into l_count from emp
where e.mgr = empno and ename = 'KING';
if l_count != 0 then
dbms_output.put_line(e.ename);
end if;
end loop;
end;
No comments:
Post a Comment