【问题标题】:Issue with referencing column in Oracle inline viewOracle 内联视图中的引用列问题
【发布时间】:2014-02-28 03:14:40
【问题描述】:

我有三张桌子作为主人,孩子和孙子。简化如下:

CREATE TABLE TABLE1
(
  ID          NUMBER(10) NOT NULL,
  TIME_STAMP  DATE NOT NULL,
  COL1        VARCHAR2(64 CHAR) NOT NULL
)

CREATE TABLE TABLE2
(
  ID           NUMBER(10) NOT NULL,
  TIME_STAMP   DATE NOT NULL,
  TABLE1_ID    NUMBER(10) NOT NULL,
  COL2         VARCHAR2(64 CHAR) NOT NULL,
)

ALTER TABLE TABLE2 ADD (
  CONSTRAINT TABLE2_FK 
  FOREIGN KEY (TABLE1_ID) 
  REFERENCES TABLE1 (ID))
/

CREATE TABLE TABLE3
(
  ID          NUMBER(10) NOT NULL,
  TIME_STAMP  DATE NOT NULL,
  TABLE2_ID   NUMBER(10) NOT NULL,
  COL3        VARCHAR2(255 CHAR) NOT NULL
)

ALTER TABLE TABLE3 ADD (
  CONSTRAINT TABLE3_FK 
  FOREIGN KEY (TABLE2_ID) 
  REFERENCES TABLE2 (ID))
/

在更大的查询中,我将这三个表加入到这样的内联视图中:

SELECT * FROM (
  SELECT *
    FROM table3 tbl3
    JOIN table2 tbl2
      ON tbl3.table2_id = tbl2.id
    JOIN table1 tbl1
      ON tbl2.table1_id = tbl1.id
   WHERE tbl2.col2 = 'SOME_CODE'
     AND tbl1.col1 = 'SOME_CODE'
     AND tbl3.time_stamp > TO_DATE('20130901','YYYYMMDD')
) WHERE time_stamp < :query_date

我的问题是我没有在 where 子句中指定哪个 time_stamp 引用。令人惊讶的是,我没有收到任何错误,而是数据库决定使用 table1.time_stamp 列!我的第一个问题是为什么我没有得到“ORA-00918: column ambiguously defined”?我花了一些时间来发现问题,但是当找到问题后,通过在内联视图的选择中指定我在这种情况下感兴趣的列 tbl3.time_stamp 很容易纠正。在测试时,我确实发现如果我在列列表中包含两个 time_stamp,那么正如预期的那样,我将得到 ORA-00918。

请帮帮我,我在这里遗漏了什么还是 Oracle 11 中的内联视图存在一些问题(错误或功能)?

【问题讨论】:

    标签: sql oracle oracle11g inline-view


    【解决方案1】:

    有趣的是,如果我们尝试使用 dbms_sql.describe 过程获取查询中的列名,我们可以看到三个相似的名称“time_stamp”和“id”:

    SQL> declare
      2   c int;
      3   clm dbms_sql.DESC_TAB;
      4   c_n int;
      5  begin
      6    c := dbms_sql.open_cursor;
      7    dbms_sql.parse(c => c
      8    , statement => 'SELECT * FROM ( SELECT * '||
      9      'FROM table3 tbl3 JOIN table2 tbl2 ON tbl3.table2_id = tbl2.id '||
     10      'JOIN table1 tbl1 ON tbl2.table1_id = tbl1.id WHERE tbl2.col2 = ''SOME_CODE'''||
     11      ' AND tbl1.col1 = ''SOME_CODE''' ||
     12      ' AND tbl3.time_stamp > TO_DATE(''20130901'',''YYYYMMDD'')) where time_stamp < sysdate'
     13    , language_flag => dbms_sql.native);
     14    dbms_sql.describe_columns(c => c
     15    , col_cnt => c_n
     16    , desc_t => clm
     17    );
     18    for i in 1..c_n loop
     19      dbms_output.put_line(clm(i).col_name);
     20    end loop;
     21    dbms_sql.close_cursor(c);
     22  end;
     23  /
    ID                                                                              
    TIME_STAMP                                                                      
    TABLE2_ID                                                                       
    COL3                                                                            
    ID                                                                              
    TIME_STAMP                                                                      
    TABLE1_ID                                                                       
    COL2                                                                            
    ID                                                                              
    TIME_STAMP 
    

    但如果你从 JOIN 语法来加入 WHERE 子句,你会得到 ORA-00918:

    SQL> SELECT * FROM (
      2    SELECT *
      3      FROM table3 tbl3
      4      , table2 tbl2
      5      , table1 tbl1
      6     WHERE tbl2.col2 = 'SOME_CODE'
      7       AND tbl1.col1 = 'SOME_CODE'
      8       AND tbl3.time_stamp > TO_DATE('20130901','YYYYMMDD')
      9       AND tbl3.table2_id = tbl2.id
     10       AND tbl2.table1_id = tbl1.id
     11  )
     12  where time_stamp < sysdate
     13  /
    where time_stamp < sysdate
          *
    error in line 12:
    ORA-00918: column ambiguously defined
    

    看来这只是来自 JOIN 语法的众多错误之一。

    【讨论】:

    • 谢谢,Oracle 的 ANSI 连接结合内部视图的实现似乎确实存在一些问题。
    【解决方案2】:

    需要注意的是 - 您在查询中选择 *,我猜 oracle 会自动将 time_stamp 列命名为 time_stamp、time_stamp_1、time_stamp_2。

    现在在你的 where 子句中你有 time_stamp= 这可以工作,因为它将 time_stamp 与 table1.time_stamp 联系起来。

    如果你在下面执行sql,你将能够在输出中看到上面的列名

    SELECT *
        FROM table3 tbl3
        JOIN table2 tbl2
          ON tbl3.table2_id = tbl2.id
        JOIN table1 tbl1
          ON tbl2.table1_id = tbl1.id
       WHERE tbl2.col2 = 'SOME_CODE'
         AND tbl1.col1 = 'SOME_CODE'
         AND tbl3.time_stamp > TO_DATE('20130901','YYYYMMDD')
    

    【讨论】:

    • 我认为您可能会在这里做一些事情,但我认为如果这应该是真的,那么逻辑上 table3.time_stamp 作为列表中的第一个应该是名为 time_stamp 的那个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-27
    • 2017-04-27
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多