这个 Oracle SQL SELECT 不应该工作。为什么会这样呢?

Sag*_*ner 8 sql oracle

SELECT DISTINCT我正在 Oracle 19c 中调试一个查询,该查询试图按不在查询中的字段对结果进行排序。(注意:这是错误的做法,请勿这样做。

此查询尝试返回一个唯一的客户名称列表,首先按最近的销售日期排序。它返回预期错误“ORA-01791:不是 SELECTed 表达式”。

SELECT DISTINCT CUSTOMER_NAME
FROM SALES
ORDER BY LAST_SALE_DATE DESCENDING;
Run Code Online (Sandbox Code Playgroud)

它返回错误,因为查询尝试按尚未选择的字段对结果进行排序。到目前为止这是有道理的。

但是,如果我只是添加FETCH FIRST 6 ROWS ONLY到查询中,它不会返回错误(尽管结果不正确,所以不要这样做)。但问题是为什么Oracle不返回错误信息呢?

SELECT DISTINCT CUSTOMER_NAME
FROM SALES
ORDER BY LAST_SALE_DATE DESCENDING
FETCH FIRST 6 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)

为什么添加会FETCH FIRST 6 ROWS ONLY起作用?

补充:如果有多个具有相同名称和日期的记录,则错误的查询将返回重复项。搜索诸如“sql select unique order by another column”之类的内容将显示几种正确的方法来执行此操作。

小智 8

查询的解释计划显示了正在发生的情况。

解析器重写该fetch...子句 - 它将分析添加row_numberselect列表中,并使用带有行号过滤器的外部查询。它将unique指令(distinct来自您的指令select)推送到子查询中,这不是有效的转换;我认为这是Oracle 实现中的一个明显错误fetch...

解释计划显示了解析器在应用时创建内联视图unique并添加分析的步骤row_number()。它不显示投影(视图中包含哪些列),以及 - 重要的是 - 它适用于什么unique。不过,一点点实验就给出了答案:它适用unique于和的组合customer_namelast_sales_date

有可能这个问题已经被报告过,并且可能在最近的版本中得到了修复 - 您的 Oracle 版本是什么?

  • `dbms_utility.expand_sql_text` 似乎显示了完整生成的查询。(“似乎”是因为我不知道这是否是实际的最终转换。)它厚颜无耻地在内联视图中添加“order by”子句中提到的列,然后在封闭的查询中生成“row_number()”表达式,最后从结果中选择“customer_name”,并使用“where”子句来限制行。 (3认同)
  • 它可以在 [db<>fiddle 21c XE 实例](https://dbfiddle.uk/?rdbms=oracle_21&fiddle=b7bd05b5a49d2a8f1e7a99be898937d2) 上重现 (2认同)
  • @APC - 我想知道这是否已报告给 Oracle。我不是付费客户(无论如何我都不是客户,我只是一个为了自己的娱乐而使用 Oracle 的爱好者),所以我无法获得客户支持 - 我无法检查出现了哪些错误报道称。如果有访问权限的人愿意检查,这将是值得分享的好信息。 (2认同)