yangtingkun
===========================================================
ROWNUM伪列返回空
===========================================================

今天又碰到一个奇怪的错误,ROWNUM伪列的值居然返回空。


首先重现一下错误:

SQL> CREATE TABLE T AS SELECT * FROM DBA_OBJECTS;

表已创建。

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

只要将ROWNUM放到查询的外层,就没有错误了:

SQL> SELECT ROWNUM RN, A.* FROM
2 (
3 SELECT ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
4 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
5 WHERE ROWNUM < 10
6 ) A;

RN RN_OVER
---------- ----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

已选择9行。

进一步观察发现,问题不仅和ROWNUM的位置有关,还与分析函数ROW_NUMBER() OVER()有关。换成其他的分析函数,则不会出现这个问题:

SQL> SELECT ROWNUM RN, COUNT(*) OVER(ORDER BY OBJECT_NAME) CNT
2 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN CNT
---------- ----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

已选择9行。

SQL> COL MAX FORMAT A45
SQL> SELECT ROWNUM RN, MAX(OBJECT_NAME) OVER(ORDER BY OBJECT_NAME) MAX
2 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN MAX
---------- ---------------------------------------------
1 /1005bd30_LnkdConstant
2 /10076b23_OraCustomDatumClosur
3 /1025308f_SunTileScheduler
4 /10297c91_SAXAttrList
5 /103a2e73_DefaultEditorKitEndP
6 /1048734f_DefaultFolder
7 /10501902_BasicFileChooserUINe
8 /105072e7_HttpSessionBindingEv
9 /106ba0a5_ArrayEnumeration

已选择9行。

而且,问题还与内层查询有关,当内层查询包括GROUP BYDISTINCT/UNIQUEORDER BY等操作时,会出现这个问题:

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT OBJECT_NAME FROM T GROUP BY OBJECT_NAME)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT OBJECT_NAME FROM T ORDER BY OBJECT_NAME)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

已选择9行。

而且,问题还与分析函数ROW_NUMBER() OVER()中的排序字段有关:

SQL> SELECT ROWNUM RN,
2 ROW_NUMBER() OVER(ORDER BY OBJECT_TYPE) RN_OVER
3 FROM
4 (
5 SELECT OBJECT_TYPE, CREATED, COUNT(*) CN
6 FROM T
7 GROUP BY OBJECT_TYPE, CREATED
8 )
9 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

SQL> SELECT ROWNUM RN,
2 ROW_NUMBER() OVER(ORDER BY CREATED) RN_OVER
3 FROM
4 (
5 SELECT OBJECT_TYPE, CREATED, COUNT(*) CN
6 FROM T
7 GROUP BY OBJECT_TYPE, CREATED
8 )
9 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

已选择9行。

SQL> SELECT ROWNUM RN,
2 ROW_NUMBER() OVER(ORDER BY CREATED) RN_OVER
3 FROM
4 (
5 SELECT OBJECT_TYPE, CREATED, COUNT(*) CN
6 FROM T
7 GROUP BY CREATED, OBJECT_TYPE
8 )
9 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

最后,这个错误在9204中出现,在10g中已经不再出现:

SQL> SELECT * FROM V$VERSION;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 -
Production PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1
2
3
4
5
6
7
8
9

已选择9行。

SQL> CONN YANGTK/YANGTK@YTK已连接。
SQL> CREATE TABLE T AS SELECT * FROM DBA_OBJECTS;

表已创建。

SQL> SELECT ROWNUM RN, ROW_NUMBER() OVER(ORDER BY OBJECT_NAME) RN_OVER
2 FROM (SELECT DISTINCT OBJECT_NAME FROM T)
3 WHERE ROWNUM < 10;

RN RN_OVER
---------- ----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

已选择9行。

根据上面的测试,基本上可以判断,子查询中首先对某个字段进行了排序,而外层的ROW_NUMBER() OVER()中也对这个字段进行排序的话,那么与ROW_NUMBER() OVER()分析函数同层的ROWNUM会返回NULL

查询了一下METALINK,发现果然是Oraclebugbug号:3760380Oracle9208、10.1.0.410.2.0.1中解决了这个BUG。不过METALINK上没有给出详细的错误原因,以及何时可能导致错误出现,甚至没有给出解决办法。

yangtingkun 发表于:2006.10.27 19:58 ::分类: ( ORACLE , Bug ) ::阅读:(3514次) :: 评论 (3)
re: ROWNUM伪列返回空 [回复]

反序排就能查出来了

SELECT ROWNUM RN, COUNT(*) OVER(ORDER BY BJECT_NAME desc) CNT
FROM (SELECT DISTINCT OBJECT_NAME FROM T)
WHERE ROWNUM <10>

Ronny 评论于: 2007.05.22 16:04
re: ROWNUM伪列返回空 [回复]

你没有仔细看测试的步骤
使用count(*) over()的话,正排序也可以得到结果。

yangtingkun 评论于: 2007.05.23 21:40
re: ROWNUM伪列返回空 [回复]

ORACLE BUG还真多。

Eason.Cai 评论于: 2007.11.24 14:55

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...