Oracle UNION和ORDER BY的奇怪问题

时间:2014-08-19 15:58:38

标签: sql oracle oracle11g sql-order-by union-all

以下查询在几乎每个数据库中都是perfectly valid(提供或采用dual虚拟表),包括Oracle:

select 'A' as x from dual union all
select 'B'      from dual
order by x asc

返回:

| X |
|---|
| A |
| B |

现在这个查询仍然是非常标准的SQL,但是Oracle上的doesn't work

select 'A' as x from dual union all
select 'B'      from dual union all
select 'C'      from dual
order by x asc

我正在

ORA-00904: "X": invalid identifier

但是,works

select 'A' as x from dual union all
select 'B' as x from dual union all
select 'C'      from dual
order by x asc

我一直在玩这个问题,并且发现显然,至少第一个子选择和倒数第二个(??)子选择需要有一个名为{{的列1}}。在第一个例子中,两个子选择似乎只是重合。 Working example

x

正如您可能已经猜到的那样,wouldn't work

select 'A' as x from dual union all
select 'B'      from dual union all
select 'C'      from dual union all
select 'D'      from dual union all
select 'E'      from dual union all
select 'F' as x from dual union all
select 'G'      from dual
order by x asc

有趣的附注:

派生表似乎没有受到此限制。 This works

select 'A' as x from dual union all
select 'B'      from dual union all
select 'C'      from dual union all
select 'D'      from dual union all
select 'E' as x from dual union all
select 'F'      from dual union all
select 'G'      from dual
order by x asc

问题:

这是Oracle SQL解析器中的一个(已知?)错误,还是语言语法中有任何非常细微的细节,绝对需要第一个和倒数第二个子选择来保存从select * from ( select 'A' as x from dual union all select 'B' from dual union all select 'C' from dual ) order by x asc 条款?

2 个答案:

答案 0 :(得分:8)

这并没有真正回答这个问题,但它似乎是一个解析器错误(或“功能”),而不是语言要求。

根据我的Oracle支持,这似乎已被提出为错误14196463,但没有解决方案关闭。它也在community thread 3561546中提到过。您需要一个MOS帐户或至少一个Oracle帐户来查看其中任何一个。

据我所知,还讨论了in an OTN thread,它需要基本的Oracle登录而不是MOS帐户。这也没有太多的信息,但重复你的发现,并且还表明这种行为至少存在于9.2.0.8,可能还要早得多。

The documentation有点含糊不清,但并未表明预计会出现问题:

  

对于包含集合运算符UNIONINTERSECTMINUSUNION ALL的复合查询,ORDER BY子句必须指定位置或别名而不是显式表达式。此外,ORDER BY子句只能出现在最后一个组件查询中。 ORDER BY子句对整个复合查询返回的所有行进行排序。

您正在使用该表达式别名,并且它并没有说您必须为特定组件添加别名(当然,它并不表示您必须)。< / p>

该行为似乎与别名对最终投影有效不一致,并且关于别名的通常规则仅在order by子句中有效 - 这似乎在介于两者之间的某处。

答案 1 :(得分:4)

这不能回答为什么你从当前查询中获得不一致的行为,但是在Oracle中你可以轻松地重写如下(它应该永远不会因标识符错误而失败):

with t(x) as (
  select 'A' from dual
  union all
  select 'B' from dual
  union all
  select 'C' from dual
)
select * from t
order by x asc

额外的好处是你只需要指定列别名(x)一次。