在Oracle数据库中,ROWID是一个伪列(pseudocolumn),它代表了表中每一行的物理地址。ROWID包含了数据对象号、数据文件号、数据块号以及行号等信息,因此它是唯一且不变的(除非发生行迁移等特殊情况)。
1. 语法问题:* 的特殊性
SELECT * 表示选择表中所有用户定义的列(不包括伪列如 ROWID、ROWNUM 等)。
当直接组合 ROWID, * 时,Oracle 无法解析这种写法,因为它违反了语法规则:
sql
-- 错误写法(直接报错 ORA-00936)SELECT ROWID, * FROM employees;
2. 解决方案:使用表别名限定
通过表别名明确指定作用域即可解决:
sql
-- 正确写法:用别名限定SELECT t.ROWID, t.* FROM employees t;
为什么有效?
t.* 明确表示选择表 t 的所有列(不包括伪列)。
t.ROWID 明确指向表 t 的伪列。
此时两者作用域清晰,无歧义。
3. 根本原因分析
* 的解析规则:
Oracle 要求 * 必须被限定(如 表名.* 或 别名.*)。直接使用 * 只能单独出现(如 SELECT *),不能与其他列混用。
伪列的特殊性:
ROWID 是伪列(Pseudocolumn),不属于用户定义的列。它与 * 代表的列集合存在逻辑冲突。
4. 其他替代写法
显式列出所有列(不推荐):
· SELECT ROWID, employee_id, first_name, ... FROM employees;
·子查询(可行但冗余):
SELECT ROWID, t.* FROM (SELECT * FROM employees) t;
总结
场景 | 写法 | 结果 |
|---|---|---|
直接组合 ROWID, * | SELECT ROWID, * FROM 表名; | 报错 ORA-00936 |
用别名限定作用域 | SELECT 别名.ROWID, 别名.* FROM 表名 别名; | 成功执行 |
关键点:始终用表别名限定 ROWID 和 *(如 t.ROWID, t.*),即可避免语法错误。这是Oracle的明确语法要求。
总结原因:1. 当使用`*`时,它表示选择表中的所有列,包括伪列ROWID(实际上`*`并不包括伪列,但这里的问题不是重复)。实际上,问题在于当使用`*`时,如果同时单独选择ROWID,在没有表别名的情况下,Oracle无法正确解析。2. Oracle要求当使用表别名时,所有列(包括伪列)都应该用别名限定。因此,为了避免错误,当需要同时选择ROWID和所有列时,应该使用表别名,并且用别名限定ROWID和`*`。注意:在Oracle中,`*`并不包括伪列(如ROWID, ROWNUM等),所以理论上选择ROWID和`*`并不会造成重复列。但是,由于语法解析的原因,直接同时使用ROWID和`*`而不加别名限定是不允许的。所以,根本原因在于Oracle的语法解析要求,当使用`*`时,如果还有其他列,那么整个选择列表需要明确。而使用表别名可以明确每个列的来源,从而避免歧义。




