现象
Q提出想要把tableA表按照col2列排序后,找出第5-10行记录。咋搞?
讲知识
按照特定条件查找出前N行数据,可以通过ROWNUM解决。
ROWNUM又被称为伪列,伪列就像在在表中有这么一列,但并不存储在表中,能够基于伪列进行从查询,也能够基于ROWNUM进行更新删除操作,例如
SELECT * FROM tableA t
WHERE ROWNUM < 3;
UPDATE tableA t
SET t.col2 = '201706'
WHERE ROWNUM < 2;
DELETE FROM tableA t
WHERE ROWNUM < 3;
不过由于ROWNUM会随着条件限制、表记录更改等发生变化,并不是表记录的真实值,所以尽量避免用ROWNUM来进行删改操作。
ROWNUM支持能够查出正确记录的操作符为<code><</code>、<code><=</code>、<code>!=</code>、<code>=1</code>,对于<code>></code>、<code>>=</code>、<code>=N(N>1)</code>、<code>BETWEEN…AND…</code>运行时不报错,但直接使用不能查询出正确结果。
ROWNUM是在查询出结果集后,给结果集添加上一个伪列,类似于给查询出的结果标上序号,序号从1开始,连续递增,不存在序号跳跃的现象。例如:
SELECT ROWNUM, t.name FROM tableA t;
结果为:
1 gulu
2 gaolaozhuang
3 daideng
4 qinqiang
如果加上限制条件:
SELECT ROWNUM, t.name FROM tableA t WHERE t.name NOT LIKE 'd%';
结果为:
1 gulu
2 gaolaozhuang
3 qinqiang
原来第4行会变成第3行,所以如果用<code>WHERE ROWNUM > 3</code>来进行查询时,并不会有任何结果,因为第一条记录(ROWNUM=1)不满足条件被去掉后,原第二条记录就成为第一条记录(ROWNUM=1),仍旧不满足被去掉,以此类推,所以永远不会有大于3的记录。由此,使用<code>ROWNUM != 2</code>与<code>ROWNUM < 2</code>等价。
回到刚开始的问题,既然ROWNUM不支持BETWEEN…AND…,>号这些,那如何得到第5-10行记录呢?
可以通过使用子集查询来解决:
SELECT B.RID, B.COL2
FROM (SELECT ROWNUM RID, A.COL2
FROM (SELECT T.COL2 FROM TABLEA T ORDER BY T.COL2) A
WHERE ROWNUM <= 10) B
WHERE B.RID >= 5
使用了两次子集查询,第一次是按照col2进行排序,确保使用ROWNUM得到的是有序的结果集,第二次是用ROWNUM找出前10行记录,并将ROWNUM起别名RID保存到临时表,最后通过RID来限制第5行以后记录。这样就得到了第5-10有序记录。
对于为何先使用ORDER BY 再使用ROWNUM<=10的解释:
If an ORDER BY clause follows ROWNUM in the same query, then the rows will be reordered by the ORDER BY clause. The results can vary depending on the way the rows are accessed. For example, if the ORDER BY clause causes Oracle to use an index to access the data, then Oracle may retrieve the rows in a different order than without the index.
对于刚开始的问题,还可以使用以下子集查询进行解决:
使用MINUS
SELECT ROWNUM RID, A.COL2
FROM (SELECT T.COL2 FROM TABLEA T ORDER BY T.COL2) A
WHERE ROWNUM <= 10
MINUS
SELECT ROWNUM RID, A.COL2
FROM (SELECT T.COL2 FROM TABLEA T ORDER BY T.COL2) A
WHERE ROWNUM < 5
使用INTERSECT
SELECT TT.RID, TT.COL2
FROM (SELECT ROWNUM RID, A.COL2
FROM (SELECT T.COL2 FROM TABLEA T ORDER BY T.COL2) A) TT
WHERE TT.RID >= 5
INTERSECT
SELECT ROWNUM RID, A.COL2
FROM (SELECT T.COL2 FROM TABLEA T ORDER BY T.COL2) A
WHERE ROWNUM <= 10