TABLE / CAST / MULTISET与FROM子句中的子查询

时间:2015-06-02 14:19:00

标签: sql oracle oracle11g

以下查询不起作用。由于temp.col引用了在该上下文中不可用的内容,因此预计会失败。

with temp as  (
       select 'A' col from dual
       union all
       select 'B' col from dual
     )
select *
from temp,
     (select level || temp.col from dual connect by level < 3);

来自Oracle的错误消息是:ORA-00904:“TEMP”。“COL”:标识符无效

但为什么下一个查询有效呢?我将CAST / MULTISET视为从SQL表转换为集合类型的一种方式,而TABLE则返回到SQL表。为什么我们使用这种往返旅行?我想让查询工作,但是怎么做?

with temp as  (
       select 'A' col from dual
       union all
       select 'B' col from dual
     )
select *
from temp,
     table(
       cast(
         multiset(
           select level || temp.col from dual connect by level < 3
         ) as sys.odcivarchar2list
       )
     ) t;

结果是:

COL COLUMN_VALUE
--- ------------
A   1A          
A   2A          
B   1B          
B   2B          

查看第二列的名称COLUMN_VALUE。看起来像构造CAST / MULTISET或TABLE之一生成的名称。

修改

通过下面接受的答案,我检查了文档,发现TABLE机制是一个表集合表达式。圆括号之间的表达式是集合表达式。文档定义了一种称为左相关的机制:

  

collection_expression可以引用定义到的表的列   它在FROM子句中的左边。这称为左相关。剩下   只能在table_collection_expression中发生相关。其他   子查询不能包含对外部定义的列的引用   子查询。

所以这就像12c中的LATERAL。

1 个答案:

答案 0 :(得分:2)

Oracle允许lateral内联视图引用内联视图中的其他表。

在旧版本中,此功能主要用于优化,如Oracle优化器博客here中所述。在12c中添加明确的侧向连接。您的第一个查询只需要在12c中进行一些小改动:

with temp as  (
       select 'A' col from dual
       union all
       select 'B' col from dual
     )
select *
from temp,
     lateral(select level || temp.col from dual connect by level < 3);

显然,Oracle也默默地使用横向连接进行收集取消。在某些情况下,SQL使用逻辑交叉连接,但这些表明显密切相关;例如XMLTable,JSON_table和查询就像你的第二个例子。在这些情况下,将两个表一起执行是有意义的。我假设在那里使用了横向机制,尽管执行计划和10053优化器跟踪都没有使用单词&#34; lateral&#34;。文档甚至在Collection Unnesting: Examples中有一个与您的非常相似的示例。然而,这个&#34;功能&#34;仍然没有很好的记录。

另一方面,您应该避免使用增加上下文的SQL功能。横向连接,公用表表达式和相关子查询等功能可能很有用,但它们也会使SQL语句更难理解。常规内联视图可以单独运行和理解,并且具有非常简单的界面 - 其投影列。这种简单性使得将小组件组装成大型语句变得更容易。

我建议你重新编写你的查询,如下所示。像处理函数或过程一样处理每个内联视图 - 为它们提供好的名称和注释。当你将它们组装成大而实际的陈述时,它会帮助你。

select col, the_level||col
from
(
    --Good comment 1.
    select 'A' col from dual union all
    select 'B' col from dual
) good_name_1
cross join
(
    --Good comment 2.
    select level the_level
    from dual
    connect by level < 3
) good_name_2