【问题标题】:select running by itself but not in subquery选择自行运行但不在子查询中
【发布时间】:2022-01-10 16:48:48
【问题描述】:

好的,所以我遇到了一些问题,需要您的帮助。 这怎么能正常运行:

select salary from employees
            where job_id = 'AD_PRES' and rownum <= 5
            order by salary desc

这不是吗?

select * from employees
      where 
      salary in
(     
      select salary from employees
            where job_id = 'AD_PRES' and rownum <= 5
      order by salary desc
)

我得到的错误是:00907. 00000 - "missing right parenthesis"

【问题讨论】:

  • 我不是 Oracle 专家,但一般来说,您不能在派生表表达式中使用 ORDER BY
  • IN 子句是集合操作,。没有排序顺序,对父查询没有影响。
  • where 子句在order by 之前应用,因此排序对过滤没有影响
  • rownum 并不像您认为的那样。仅使用 FETCH FIRST 5 ROWS

标签: sql oracle


【解决方案1】:

在 SQL 中,一般来说,表的顺序是不确定的,不能保证顺序。

您的查询:

select salary
from   employees
where  job_id = 'AD_PRES'
and    rownum <= 5
order by salary desc;

将以非确定性(随机)顺序从表中获取行1,然后它将应用 WHERE 子句以仅包含 job_id = 'AD_PRES' 并分配 ROWNUM 伪的行- 列值按读取顺序排列,并在找到 5 行后停止。 之后,它将按薪水顺序排列前(随机)5 行。

您想要的是在使用ROWNUM 过滤之前应用ORDER BY 子句:

SELECT salary
FROM   (
  SELECT salary
  FROM   employees
  WHERE  job_id = 'AD_PRES'
  ORDER BY salary DESC
)
WHERE  rownum <= 5

从 Oracle 12 开始,有一个更简单的语法:

SELECT salary
FROM   employees
WHERE  job_id = 'AD_PRES'
ORDER BY salary desc
FETCH FIRST 5 ROWS ONLY;

这怎么能正常运行……而这不行?

正如@OldProgrammer 所说,因为IN 是一个集合操作,并且对无序集合应用顺序没有意义,并且语法不允许在这种情况下使用ORDER BY 子句。引发 "missing right parenthesis" 错误是因为 Oracle 不希望 IN 列表中出现 ORDER BY 子句,而是希望子查询以右括号结束

您需要做的是在子查询的最外层查询中使用不带ORDER BY 的查询,或者使用新的FETCH 语法。

select *
from   employees
where  salary in (
  SELECT salary
  FROM   (
    SELECT salary
    FROM   employees
    WHERE  job_id = 'AD_PRES'
    ORDER BY salary DESC
    -- You can use `ORDER BY` in a nested sub-query
  )
  WHERE  rownum <= 5
  -- No ORDER BY clause in the outer-most sub-query of an IN expression
)

或:

select *
from   employees
where  salary in (
  SELECT salary
  FROM   employees
  WHERE  job_id = 'AD_PRES'
  ORDER BY salary DESC
  FETCH FIRST 5 ROWS ONLY
)

db小提琴here


  1. 由于它的实现方式,它可能看起来是一个确定性(非随机)顺序,因为从数据文件中读取的行是一致的顺序。但是,这永远无法保证,并且在某些情况下行的顺序会发生变化;尤其是在并行系统上或当表启用了行移动时。

【讨论】:

  • 关于脚注:如果表中的某些数据已被缓冲(来自早期读取),则行也可能以不同的顺序读取。 Oracle 可以选择从缓冲区中读取——不管里面发生了什么;无法控制将在那里找到哪些行,并且它可能会从一次执行更改为下一次执行。
  • 另外关于脚注 - 优化器可能会选择一个使用子查询索引的执行计划,这再次可能会改变它碰巧检索行的顺序。或者数据可能会被某些计划任务移动或压缩。我已经看到生产失败,其中查询依赖于“默认”排序,直到它没有。
猜你喜欢
  • 2010-10-09
  • 2013-11-20
  • 2017-04-25
  • 2013-09-14
  • 2013-09-22
  • 2011-06-26
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多