Oracle9204上执行一个明显语法错误的SQL,却可以得到查询结果。
首先重现一下问题:
SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS;
表已创建。
SQL> CREATE TABLE T2 AS SELECT * FROM DBA_USERS;
表已创建。
SQL> SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE;
SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE
*第 1 行出现错误:
ORA-00979: 不是 GROUP BY 表达式
这个SQL由于GROUP BY语句中确少OWNER字段,因此执行报错。
但是把这个SQL内嵌到子查询中,居然可以得到结果:
SQL> SELECT USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
USERNAME OBJECT_TYPE CN
------------------------------ ------------------ ----------
SYS LOB 28
SYS TYPE 478
SYS VIEW 2112
.
.
.
SYSTEM INDEX PARTITION 48
SYSTEM TABLE PARTITION 53
已选择42行。
检查SQL的执行计划,发现是MERGE JOIN:
SQL> SELECT USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 MERGE JOIN
3 2 SORT (JOIN)
4 3 TABLE ACCESS (FULL) OF 'T2'
5 2 SORT (JOIN)
6 5 TABLE ACCESS (FULL) OF 'T1'
想想也有道理,Oracle先对OWNER字段进行排序,进行MERGE JOIN连接后,再对OBJECT_TYPE字段进行GROUP BY。
如果使用HASH_JOIN提示,Oracle也可以得到执行结果:
SQL> SET AUTOT TRACE EXP
SQL> SELECT /* USE_HASH(T2) */ USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
执行计划
IXDBA.NET社区论坛
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=54 Card=1467 Bytes=76284)
1 0 SORT (GROUP BY) (Cost=54 Card=1467 Bytes=76284)
2 1 HASH JOIN (Cost=45 Card=1467 Bytes=76284)
3 2 TABLE ACCESS (FULL) OF 'T2' (Cost=2 Card=2 Bytes=48)
4 2 TABLE ACCESS (FULL) OF 'T1' (Cost=42 Card=5867 Bytes=164276)
不过这个SQL也很有意思,只需要将上面的USERNAME改成OWNER,就会报错:
SQL> SELECT OWNER, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
WHERE USERNAME = OWNER
*第 3 行出现错误:
ORA-00979: 不是 GROUP BY 表达式
这时即使加上HINT也不行:
SQL> SELECT /* USE_HASH(T2) */ OWNER, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE) T1, T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
WHERE USERNAME = OWNER
*第 3 行出现错误:
ORA-00979: 不是 GROUP BY 表达式
这个问题在10R2中只能通过RULE方式再现,通过使用USE_MERGE和USE_HASH提示已经无法再现了:
SQL> CONN TEST/TEST@TESTZJ已连接。
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS;