11. Advanced Searching
Paginating Through a Result Set
We want to paginate a result set. For example, we want to return the first five rows from a table, then the next five, and so forth.
with series as 
(
select rownum id, level*10 data from dual 
connect by level <= 10
) 
select * from series where id between 1 and 5;Skipping n Rows from a Table
We want to skip the second or fourth or nth row from a result set.
-- Skip even-numbered rows
select ename
from (
    select row_number() over (order by ename) rn,
    ename
    from emp
) x
where mod(rn,2) = 1Incorporating OR Logic When Using Outer Joins
We want to return the name and department information for all employees in departments 10 and 20 along with department information for departments 30 and 40 (but no employee information).
-- Solution 1
select e.ename, d.deptno, d.dname, d.loc
from dept d left join emp e
on (d.deptno = e.deptno and (e.deptno=10 or e.deptno=20))
order by 2
-- Solution 2
SELECT
    e.ename,
    d.deptno,
    d.dname,
    d.loc
FROM
    dept d
    LEFT JOIN (
        SELECT
            ename,
            deptno
        FROM
            emp
        WHERE
            deptno IN ( 10, 20 )
    )    e ON ( e.deptno = d.deptno )
ORDER BY
    2Selecting the Top n Records
We want to limit a result set to a specific number of records based on a ranking of some sort. For example, you want to return the names and salaries of the employees with the top five salaries.
-- Top five salaries employee
select ename,sal
from (
    select ename, sal,
    dense_rank() over (order by sal desc) dr
    from emp
) x
where dr <= 5
-- Fetch first 5 rows from the employees table ordered by hire_date
SELECT
    employee_id,
    first_name,
    last_name,
    hire_date
FROM
    employees
ORDER BY
    hire_date
FETCH FIRST 5 ROWS ONLY;Finding Records with the Highest and Lowest Values
We want to find the employees with the highest and lowest salaries in table EMP.
select ename
from (
    select ename, sal,
    min(sal)over() min_sal,
    max(sal)over() max_sal
    from emp
) x
where sal in (min_sal,max_sal)Investigating Future Rows
We want to find any employees who earn less than the employee hired immediately after them. Based on the following result set: ENAME SAL HIREDATE
ENAME SAL HIREDATE
---------- ---------- ---------
SMITH 800 17-DEC-80
ALLEN 1600 20-FEB-81
WARD 1250 22-FEB-81
JONES 2975 02-APR-81
BLAKE 2850 01-MAY-81
CLARK 2450 09-JUN-81
TURNER 1500 08-SEP-81
MARTIN 1250 28-SEP-81
KING 5000 17-NOV-81
JAMES 950 03-DEC-81
FORD 3000 03-DEC-81
MILLER 1300 23-JAN-82
SCOTT 3000 09-DEC-82
ADAMS 1100 12-JAN-83SMITH, WARD, MARTIN, JAMES, and MILLER earn less than the person hired immediately after they were hired, so those are the employees you want to find with a query.
SELECT
    ename,
    sal,
    hiredate
FROM
    (
        SELECT
            ename,
            sal,
            hiredate,
            LEAD(sal) OVER( ORDER BY hiredate ) next_sal
        FROM
            emp
    ) alias
WHERE
    sal < next_salShifting Row Values
We want to return each employee’s name and salary along with the next highest and lowest salaries. If there are no higher or lower salaries, then results to wrap (first SAL shows last SAL and vice versa)
Sample result set

select ename,sal,
coalesce(lead(sal)over(order by sal),min(sal)over()) forward,
coalesce(lag(sal)over(order by sal),max(sal)over()) rewind
from empRanking Results
We want to rank the salaries in table EMP like below while allowing for ties.

-- To allow for ties, use the window function DENSE_RANK OVER
select dense_rank() over(order by sal) rnk, sal
from empSuppressing Duplicates
We want to find the distinct different job types in table EMP
-- Solution 1
select distinct job
from emp;
-- Solution 2
select job
from (
    select job,
    row_number()over(partition by job order by job) rn
    from emp
) x
where rn = 1Finding Knight Values
We want to return a result set that contains each employee’s name, the department they work in, their salary, the date they were hired, and the salary of the last employee hired, in each department.
Sample result set

select deptno,
    ename,
    sal,
    hiredate,
    max(sal) keep(dense_rank last order by hiredate) over(partition by deptno) latest_sal
from emp
order by 1, 4 descGenerating Simple Forecasts
We want to return additional rows and columns representing future actions. For example, consider the following input data. We want to return three rows per row returned in the result set (each row plus two additional rows for each order). Along with the extra rows, we would like to return two additional columns providing dates for expected order processing.
Sample Input

Sample Output

WITH nrows AS (
    SELECT
        level n
    FROM
        dual
    CONNECT BY
        level <= 3
)
SELECT
    id,
    order_date,
    process_date,
    CASE
        WHEN nrows.n >= 2 THEN
            process_date + 1
        ELSE
            NULL
    END AS verified,
    CASE
        WHEN nrows.n = 3 THEN
            process_date + 2
        ELSE
            NULL
    END AS shipped
FROM
    (
        SELECT
            nrows.n               id,
            sysdate + nrows.n     AS order_date,
            sysdate + nrows.n + 2 AS process_date
        FROM
            nrows
    ) orders,
    nrowsLast updated