Based on the SQLD exam syllabusReport an error
ROWNUM = 2 and ROWNUM > 1 return 0 rows. The first row must receive number 1 before the next row can receive number 2, but the first row fails the condition.WHERE ROWNUM <= 3 ORDER BY SAL DESC first cuts off an arbitrary 3 rows and then sorts them. If you want the top 3, apply ROWNUM outside an inline view that has already been sorted.ORDER BY … FETCH FIRST n ROWS ONLY. OFFSET skips rows, and WITH TIES includes the ties at the end.SELECT TOP(n). TOP(n) WITH TIES requires an ORDER BY."The top 3 salaries" can also be found with a ranking function, but that approach ranks every row and then filters. Oracle has two mechanisms that cut the row count itself. The old way is ROWNUM, and the one introduced in 12c is FETCH FIRST.
ROWNUM is not a column stored in the table. It is a sequence number that Oracle attaches each time a query emits a row.
SELECT ROWNUM, ENAME, SAL FROM EMP WHERE ROWNUM <= 3; ROWNUM ENAME SAL
---------- ---------- ----------
1 SMITH 800
2 ALLEN 1600
3 WARD 1250Read one row
→ Check the WHERE conditions that are not ROWNUM → if it passes, assign the next number (ROWNUM)
→ Check the ROWNUM condition → if it passes, emit it as a result and increase the number by 1
→ (When all rows are done) sort with ORDER BYWHERE DEPTNO = 30 AND ROWNUM <= 3 gives 3 employees from department 30.ROWNUM = 1 returns one row. But ROWNUM = 2 has no rows at all.
SELECT COUNT(*) AS CNT FROM EMP WHERE ROWNUM = 2; CNT
----------
01 = 2 is false, so it is dropped.For the same reason, any condition that doesn't include 1 returns 0 rows.
SELECT COUNT(*) AS CNT FROM EMP WHERE ROWNUM > 1; CNT
----------
0| Condition | Number of result rows (14-row table) | Reason |
|---|---|---|
ROWNUM = 1 | 1 | The first row passes as number 1 |
ROWNUM <= 3, ROWNUM < 4 | 3 | 1, 2, 3 pass in sequence |
ROWNUM >= 1 | 14 | Every row passes |
ROWNUM = 2 | 0 | Number 1 doesn't pass, so there is no number 2 |
ROWNUM > 1 | 0 | Same as above |
ROWNUM BETWEEN 4 AND 6 | 0 | Same as above |
⚠️ Pitfall: ROWNUM conditions behave as expected only with
=1,<, and<=.ROWNUM = 2,ROWNUM > n, andROWNUM BETWEEN 2 AND …are not errors; they return 0 rows. A choice saying "it raises an error" is a wrong answer.
If you use ROWNUM and ORDER BY in the same SELECT to get the top 3, you won't get the result you want.
SELECT ROWNUM, ENAME, SAL FROM EMP WHERE ROWNUM <= 3 ORDER BY SAL DESC; ROWNUM ENAME SAL
---------- ---------- ----------
2 ALLEN 1600
3 WARD 1250
1 SMITH 800The fix is to put the sorting inside an inline view. The inner result is passed to the outside already sorted, and the outer WHERE assigns numbers in that order.
SELECT ROWNUM, ENAME, SAL FROM (SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC, ENAME) WHERE ROWNUM <= 3; ROWNUM ENAME SAL
---------- ---------- ----------
1 KING 5000
2 FORD 3000
3 SCOTT 3000ORDER BY SAL DESC, ENAME, ENAME fixes the order of the tied FORD and SCOTT. Without it, it is not determined which of the two gets number 3.To get ranks 4 to 6, use one more layer of inline view. In the middle step, give ROWNUM an alias (RN) to turn it into an ordinary column.
SELECT ENAME, SAL FROM (SELECT ROWNUM AS RN, ENAME, SAL FROM (SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC, ENAME) WHERE ROWNUM <= 6) WHERE RN >= 4;ENAME SAL
---------- ----------
JONES 2975
BLAKE 2850
CLARK 2450| Step | What it does |
|---|---|
| Innermost | Sorts by salary descending |
| Middle | Assigns ROWNUM in the sorted order and keeps up to number 6. Freezes it as the RN column |
| Outer | Keeps only the rows where RN is 4 or more. RN is now an ordinary numeric column |
From Oracle 12c, you can use the ANSI-standard row limiting clause. It goes after ORDER BY and cuts the result once sorting is done.
ORDER BY sort_column
[OFFSET number_of_rows_to_skip ROWS]
FETCH { FIRST | NEXT } n { ROW | ROWS } { ONLY | WITH TIES }FIRST and NEXT, and ROW and ROWS, mean the same thing. Pick whichever reads better.SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC, ENAME FETCH FIRST 3 ROWS ONLY;ENAME SAL
---------- ----------
KING 5000
FORD 3000
SCOTT 3000Paging shrinks from two layers of inline views to a single line.
SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC, ENAME OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;ENAME SAL
---------- ----------
JONES 2975
BLAKE 2850
CLARK 2450OFFSET 12 ROWS without FETCH, you get everything from the 13th row to the end. In EMP, that is the two rows JAMES and SMITH.FETCH FIRST 2 ROWS WITH TIES additionally fetches all rows that have the same sort value as the 2nd row. The outer ORDER BY is there to fix the display order.
SELECT * FROM (SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC FETCH FIRST 2 ROWS WITH TIES) ORDER BY SAL DESC, ENAME;ENAME SAL
---------- ----------
KING 5000
FORD 3000
SCOTT 3000ONLY, it would be exactly 2 rows. Which of FORD and SCOTT remains is not determined.| Method | When it is processed | Tie handling | Oracle version |
|---|---|---|---|
| ROWNUM | WHERE step (before sorting) | Cuts in row order | All versions |
ROW_NUMBER() OVER + inline view | SELECT step → outer WHERE | Exactly n rows | 8i and later |
RANK() OVER + inline view | SELECT step → outer WHERE | Includes ties | 8i and later |
FETCH FIRST n ROWS ONLY | After ORDER BY | Exactly n rows | 12c and later |
FETCH FIRST n ROWS WITH TIES | After ORDER BY | Includes ties at the end | 12c and later |
The approach from Day 1 is also Top N. If you make the number a column with ROW_NUMBER, you can pick a range directly with BETWEEN.
SELECT ENAME, SAL FROM (SELECT ENAME, SAL, ROW_NUMBER() OVER (ORDER BY SAL DESC, ENAME) AS RN FROM EMP) WHERE RN BETWEEN 4 AND 6 ORDER BY RN;ENAME SAL
---------- ----------
JONES 2975
BLAKE 2850
CLARK 2450BETWEEN 4 AND 6 gave 0 rows. RN is a value already calculated in the inline view, so it doesn't have that problem.PARTITION BY turns it into "top n per department". ROWNUM and FETCH FIRST cut only across the whole result, so Top N per group is the job of window functions.SQL Server uses TOP right after SELECT instead of ROWNUM or FETCH FIRST. The practice lab is Oracle, so below we only look at the syntax.
SELECT TOP(3) ENAME, SAL FROM EMP ORDER BY SAL DESC; -- 3 rows after sorting
SELECT TOP(2) WITH TIES ENAME, SAL FROM EMP ORDER BY SAL DESC; -- 2 rows + ties at the end
SELECT TOP(20) PERCENT ENAME, SAL FROM EMP ORDER BY SAL DESC; -- percentageWITH TIES must have an ORDER BY. Without one, SQL Server raises an error.TOP(3) without ORDER BY is not an error, but which 3 rows come out is not determined.SELECT TOP 3 ENAME FROM EMP in Oracle reads TOP as a column name and raises ORA-00923.| Task | Oracle | SQL Server |
|---|---|---|
| Top 3 rows after sorting | Inline view + ROWNUM <= 3, or FETCH FIRST 3 ROWS ONLY | TOP(3) + ORDER BY |
| Include ties | FETCH FIRST 3 ROWS WITH TIES, or RANK | TOP(3) WITH TIES + ORDER BY |
| 4th to 6th | Double inline view, or OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY | OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY |
Tomorrow we cover hierarchical queries (START WITH, CONNECT BY), which walk down a manager-subordinate relationship.
OFFSET … FETCH …. An ANSI-standard syntax introduced in 12c that cuts the result after ORDER BY.SELECT TOP(n).Click a choice to reveal the answer and explanation.
Question 1
EMP has 14 rows. What is the result of SELECT COUNT(*) FROM EMP WHERE ROWNUM = 2;?
Question 2
Which Oracle SQL correctly gets the top 3 salaries?
Question 3
The top salaries in EMP are KING 5000, FORD 3000, SCOTT 3000, JONES 2975, in that order. How many rows does SELECT ENAME FROM EMP ORDER BY SAL DESC FETCH FIRST 2 ROWS WITH TIES; return?
Question 4
What is the result of SELECT ENAME FROM EMP ORDER BY SAL DESC, ENAME OFFSET 2 ROWS FETCH FIRST 1 ROW ONLY;? (By salary descending, with ties by name, the order is KING, FORD, SCOTT, JONES …)
Question 5
In SQL Server, which statement gets the top 2 salaries and also includes every employee whose salary equals the 2nd place?