在墨天轮中有这么一道题 https://www.modb.pro/test/20230303,评论中有网友给出了解释,题目中是一条delete语句,为了便于说明理解,这里通过select语句说明。
create table t1 (id NUMBER,name VARCHAR2(10));
create table t2 (id NUMBER);
insert into t1 values(1,‘abcd’);
insert into t2 values(1);
commit;
SQL> SELECT * from t1 where name in (select name from t2); <–t2表中没有name列,本以为会报错,但却能执行成功
ID NAME
1 abcd
SQL> SELECT * from t1 where name in (select t1.name from t2);
ID NAME
1 abcd
SQL> SELECT * from t1 where name in (select t2.name from t2);
SELECT * from t1 where name in (select t2.name from t2)
*
ERROR at line 1:
ORA-00904: “T2”.“NAME”: invalid identifier
SQL> SELECT * from t1 where name in (select type from t2);
SELECT * from t1 where name in (select type from t2)
*
ERROR at line 1:
ORA-00904: “TYPE”: invalid identifier
SQL> SELECT * from t1 where name in (select t2.type from t2);
SELECT * from t1 where name in (select t2.type from t2)
*
ERROR at line 1:
ORA-00904: “T2”.“TYPE”: invalid identifier
通过以上查询可知子查询()中的name其实是t1.name,即原sql其实是
SELECT * from t1 where name in (select t1.name from t2);
所以若t2表不是空表,有至少一行数据,原sql将返回SELECT * from t1的结果。
若t2表是空表,原sql不会有结果返回。
mos文档 Doc ID 1327574.1 和 Doc ID 124014.1有相关的解释,这不是bug,符合ANSI/ISO SQL standard。但举了一个不太恰当的例子,说原sql可以理解为select t1.* from t1,t2;或 select t1.* from t1,t2 where t1.name=t1.name;但如果t2表的行数大于1行,结果就不一样了,如下所示。
SQL> insert into t2 values(2);
1 row created.
SQL> insert into t2 values(3);
1 row created.
SQL> select * from t1;
ID NAME
1 abcd
SQL> select * from t2;
ID
1
2
3
SQL> SELECT * from t1 where name in (select name from t2);
ID NAME
1 abcd
SQL> select t1.* from t1,t2;
ID NAME
1 abcd
1 abcd
1 abcd
SQL> select t1.* from t1,t2 where t1.name=t1.name;
ID NAME
1 abcd
1 abcd
1 abcd
SQL>
对于
select t1.id,name,t2.id
from t1,t2
where t1.id=t2.id
知道name其实是t1.name
对于原sql
SELECT * from t1 where name in (select name from t2);
一开始认为是SELECT * from t1 where name in (select t2.name from t2)执行会报错,还是没正确认识啊,实质上就是字段解析顺序的问题,若t2表有name列,会将原sql中的(select name from t2)解析为(select t2.name from t2)。若t2表没有name列但t1表有name列,会将原sql中的(select name from t2)解析为(select t1.name from t2)。