Oracle SQL命令在子查询中的问题!

时间:2011-02-25 15:38:22

标签: sql oracle

我正在尝试在Oracle SQL中运行子查询,它不会让我订购子查询列。对子查询进行排序非常重要,因为Oracle似乎随意选择返回哪一列返回主查询。

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state,
        (select last_updated from mwcrm.process_state_transition subpst
            where subpst.last_updated > pst.last_updated
            and subpst.process_state = ps.id
            and rownum = 1) as next_response
        from mwcrm.process_state ps, mwcrm.process_state_transition pst
        where ps.created_date > sysdate - 1/24
        and ps.id=pst.process_state
        order by ps.id asc

真的应该是:

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state,
        (select last_updated from mwcrm.process_state_transition subpst
            where subpst.last_updated > pst.last_updated
            and subpst.process_state = ps.id
            and rownum = 1
            order by subpst.last_updated asc) as next_response
        from mwcrm.process_state ps, mwcrm.process_state_transition pst
        where ps.created_date > sysdate - 1/24
        and ps.id=pst.process_state
        order by ps.id asc

4 个答案:

答案 0 :(得分:21)

实际上“排序”只对最外层的查询有意义 - 如果您在子查询中进行排序,则允许外部查询随意对结果进行加扰,因此子查询排序基本上没有任何内容。

看起来你只想获得大于pst.last_updated的最小last_updated - 当你把它看作最小值(聚合)时,它会更容易,而不是第一行(这带来了其他问题,就像为next_response绑定了两行一样?)

给它一个机会。公平的警告,自从我在我面前使用Oracle几年后,我不习惯子查询作为列的语法;如果爆炸了,我会在from子句中用它制作一个版本。

select
    ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state,
    (   select min(last_updated)
        from mwcrm.process_state_transition subpst
        where subpst.last_updated > pst.last_updated
          and subpst.process_state = ps.id) as next_response
from <the rest>

答案 1 :(得分:16)

dcw和Dems都提供了适当的替代查询。我只是想解释为什么你的查询没有按照你期望的方式运行。

如果您的查询包含ROWNUM和ORDER BY,Oracle首先应用ROWNUM,然后应用ORDER BY。所以查询

SELECT *
  FROM emp
 WHERE rownum <= 5
 ORDER BY empno

EMP表中获取任意5行并对其进行排序 - 几乎肯定不是预期的。如果要使用ROWNUM获取“前N行”,则需要嵌套查询。此查询

SELECT *
  FROM (SELECT *
          FROM emp
         ORDER BY empno)
 WHERE rownum <= 5

对EMP表中的行进行排序并返回前5个。

答案 2 :(得分:8)

我自己也经历过这种情况,你必须使用ROW_NUMBER()和一个额外级别的子查询,而不是rownum ......

只显示新的子查询,类似于......

(
  SELECT
    last_updated
  FROM
  (
    select
      last_updated,
      ROW_NUMBER() OVER (ORDER BY last_updated ASC) row_id
    from
      mwcrm.process_state_transition subpst
    where
      subpst.last_updated > pst.last_updated
      and subpst.process_state = ps.id
  )
    as ordered_results
  WHERE
    row_id = 1
)
  as next_response


另一种方法是使用MIN代替......

(
  select
    MIN(last_updated)
  from
    mwcrm.process_state_transition subpst
  where
    subpst.last_updated > pst.last_updated
    and subpst.process_state = ps.id
)
  as next_response

答案 3 :(得分:1)

确认的答案是完全错误的。 考虑一个生成唯一行索引号的子查询。 例如,Oracle中的ROWNUM

您需要子查询来创建用于分页目的的唯一记录号(见下文)。

考虑以下示例查询:

SELECT T0.*, T1.* FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id
JOIN 
(
SELECT DISTINCT T0.*, ROWNUM FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id
WHERE (filter...)
)
WHERE (filter...) AND (ROWNUM > 10 AND ROWNUM < 20)
ORDER BY T1.Name DESC

内部查询是完全相同的查询,但在T0上是DISTINCT。 您无法将ROWNUM放在外部查询上,因为LEFT JOIN(s)可能会产生更多结果。

如果您可以订购内部查询(T1.Name DESC),则内部查询中生成的ROWNUM将匹配。 由于您不能在子查询中使用ORDER B Y,因此数字不匹配且无用。

感谢上帝解决此问题的ROW_NUMBER OVER (ORDER BY ...)。 虽然并非所有数据库引擎都支持。

两种方法中的一种,LIMIT(不需要ORDER)和ROW_NUMBER() OVER将覆盖大多数数据库引擎。 但是,如果您没有其中一个选项,例如ROWNUM是您唯一的选项,那么子查询上的ORDER BY是必须的!