2015-06-02 148 views
3

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

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之一的生成名称。

编辑

与下面的接受的答案,我查了资料,发现表机制是表集合表达。圆括号之间的表达式是收集表达式。的单证定义了一个名为左相关机构:

的collection_expression可以引用留在FROM子句定义为 其表的列。这被称为左相关。只有在table_collection_expression中才会发生相关性 。其他 子查询不能包含对在 子查询之外定义的列的引用。

所以这就像12c中的LATERAL。

回答

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还默默采用横向加入收藏unnesting。有一些SQL使用逻辑交叉连接的情况,但这些表显然密切相关;如XMLTable,JSON_table和像你的第二个例子的查询。在这些情况下,将两个表一起执行是有意义的。我假设在那里使用横向机制,尽管执行计划和10053优化器跟踪都不使用“横向”一词。该文档甚至有一个非常类似于您的Collection Unnesting: Examples的例子。但是,这个“功能”还没有很好的记录。


在旁注中,通常应该避免使用增加上下文的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 
+0

如果我们需要使用connect by中第一个表的列,那么我猜table/cast/multiset是必须的。这将允许我们避免获得完整的交叉产品。当然我的例子是在选择列表中使用它,我们没有过滤交叉产品。 – lkuty

相关问题