为啥 Oracle 不在这里抛出“不明确的列引用”?

Posted

技术标签:

【中文标题】为啥 Oracle 不在这里抛出“不明确的列引用”?【英文标题】:Why doesn't Oracle throw an "ambiguous column reference" here?为什么 Oracle 不在这里抛出“不明确的列引用”? 【发布时间】:2018-03-27 10:46:28 【问题描述】:

我这里有几个 SQL 查询-

WITH emp AS
         (SELECT 1 AS empid, 'Adam' AS ename, 10 AS deptno, 'Broker' AS description FROM dual
          UNION ALL
          SELECT 2, 'Bob', 20, 'Accountant' FROM dual
          UNION ALL
          SELECT 3, 'Charles', 30, 'Programmer' FROM dual
          UNION ALL
          SELECT 4, 'Dan', 10, 'Manager' FROM dual
          UNION ALL
          SELECT 5, 'Eric', 10, 'Salesman' FROM dual
          UNION ALL
          SELECT 6, 'Franc', 20, 'Consultant' FROM dual),
     dept AS
         (SELECT 10 AS deptno, 'Accounts' AS dname, 100 employment_type_id FROM dual
          UNION ALL
          SELECT 20, 'Broking', 100 FROM dual
          UNION ALL
          SELECT 30, 'Corporate Relations', 200 FROM dual),
     employment_type AS
         (SELECT 100 AS employment_type_id, 'Permanent' AS description FROM dual
          UNION ALL
          SELECT 200, 'Contract' FROM dual)
/* --- Query 1
select e.ename, d.dname, e.description
  from emp e
       inner join dept d on e.deptno = d.deptno
       inner join employment_type e on d.employment_type_id = e.employment_type_id
-- */
-- /* Query 2
SELECT e.ename, d.dname, e.description
  FROM employment_type e
       INNER JOIN dept d ON e.employment_type_id = d.employment_type_id
       INNER JOIN emp e ON d.deptno = e.deptno
-- */
;

正如您在两个查询中看到的,表 empemployment_type 的别名相同,即 e

当我通过说 e.description 选择列时,我不应该收到类似

的错误消息

不明确的列引用

而且,两次查询的结果是不同的!第一个选择emp.description,第二个选择employment_type.description

请告诉我为什么会发生这种情况以及如何避免由此引起的混乱。

【问题讨论】:

我只看到一个查询有 E 别名 这里是similar question 尝试阅读此链接:***.com/questions/20246638/… 正如@NishantGupta 的链接问题的回答者所说,这看起来像是一个Oracle 错误——它肯定应该抱怨别名已被使用了两次,即使没有常见的列名。避免这种混淆的明显方法是不要在查询中两次使用相同的别名! @BasilBattikhi,一个查询被评论,另一个没有。我已经添加了它们以供大家参考我正在尝试做的事情。尝试在运行另一个查询时评论一个查询,您会看到结果的不同。我需要知道为什么 Oracle 不抛出错误。 【参考方案1】:

Oracle SQL 从未完全符合任何 ANSI/ISO SQL 标准。 例如,它从不支持from 子句中的AS

select *from dual AS d; -- fails

当前的合规状态(Oracle Compliance To Core SQL:2011 for Oracle 12c) 表明 ANSI SQL 的各种特性大多部分支持,例如:

...
E031, Identifiers:
    Oracle supports this feature, with the following exceptions:
    ...

或者,

E051, Basic query specification
    Oracle fully supports the following subfeatures:
    ...

虽然它没有提及歧义别名(或正式的范围变量),但您可能会认为差异很容易比页面中所述的更深。

我目前不知道在这种情况下如何让 Oracle 报告模棱两可,但在我看来,只注意使您的别名与众不同并不难。

您可能想知道 ANSI SQL 标准是否明确规定不允许同一范围内的重复别名。 在 SQL:2011 标准的 Part 2, SQL/Foundation 文档的 7.6 节中确实如此。 (您可以从www.wiscorp.com 下载草稿)。 具体来说,在 语法规则,10) 小节中,它说(我删掉了一点):

10) Let RV be a range variable that is exposed by TR. Let RV1 be a range variable that is exposed by a <table reference> TR1 that has the same scope clause as TR. 
   a) If RV is a <table name>, then
      i) If RV1 is a <table name>, then RV1 shall not be equivalent to RV.
      ii) Otherwise, RV1 shall not be equivalent to the <qualified identifier> of RV.
   b) Otherwise
      i) If RV1 is a <table name>, then the <qualified identifier> of RV1 shall not be equivalent to RV.
      ii) Otherwise, RV1 shall not be equivalent to RV.

这里的 RV 是可变范围,您可以看到最后一个选择适用于两个别名的情况。

我们知道主要的 SQL 品牌(SQL Server、mysql、PostgreSQL)都实施了这项检查,因此尽管来自草稿,但这些信息应该是准确的。

【讨论】:

【参考方案2】:

您可以尝试以下查询来获得结果:

这是为了:获取emp表描述

/* --- Query 1

select e.ename, d.dname, e.description
  from emp e
       inner join dept d on e.deptno = d.deptno
       inner join employment_type et on d.employment_type_id = et.employment_type_id
-- */


-- /* Query 2
SELECT e.ename, d.dname, em.description
  FROM employment_type e
       INNER JOIN dept d ON e.employment_type_id = d.employment_type_id
       INNER JOIN emp em ON d.deptno = em.deptno
-- */

根据你的代码:

您对 emp 表(作为第一个表)使用别名“e”的第一个查询。 所以它从您指定的第一个表(emp表)中获取描述。

与查询 2 相同: 它引用表就业类型(作为第一个表) 所以它会从中得到描述。

【讨论】:

以上是关于为啥 Oracle 不在这里抛出“不明确的列引用”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 OraOLEDB.Oracle GetRecordSet() 会抛出“ORA-00907:缺少右括号”错误?

为啥 printf 不在这里打印?

为啥 Java 会在这里抛出 NullPointerException?

为啥winsock 不在这里提供WSAESHUTDOWN?

为啥 g++ 不在这里执行结构打包?

当 np.where 抛出 TypeError 时,为啥 np.vectorize 在这里工作?