为什么使用"其中rownum = 1"不选择第一个有序行?

时间:2015-03-20 19:09:56

标签: sql oracle

这很奇怪,所以我可以用一双备用的眼睛来了解发生了什么。

所以我有这个问题:

WITH x as (
            SELECT num_aula, tipo_aula, min(abs(capienza-1)) score
            FROM aula
            JOIN (
                    select num_aula, tipo_aula
                    from aula
                    where tipo_aula = 'Laboratorio'
                    minus
                    select num_aula, tipo_aula
                    from occr_lezione
                    where to_char(Data_inizio_occr_lezione,'hh24:mi') = '12:30'
                    and Nome_sede = 'Centro Direzionale'
                    and Giorno_lezione = 2
                 )
            USING(num_aula,tipo_aula)
            GROUP BY num_aula, tipo_aula
            ORDER BY score asc
)
SELECT *
FROM x

返回此结果集:

NUM TIPO_AULA                 SCORE
--- -------------------- ----------
1   Laboratorio                  35
2   Laboratorio                  35

这是理想的结果。

现在,如果我将此行添加到查询中:

WHERE rownum = 1;

应该返回表格的第一行,我明白了:

NUM TIPO_AULA                 SCORE
--- -------------------- ----------
2   Laboratorio                  35

这怎么可能?

5 个答案:

答案 0 :(得分:2)

我认为您真正想要的查询是

WITH x as (
    SELECT num_aula, 
           tipo_aula, min(abs(capienza-1)) score, 
           row_number() over(partition by num_aula, tipo_aula order by score asc ) as seq
    FROM aula
    JOIN (
        select num_aula, tipo_aula
          from aula
          where tipo_aula = 'Laboratorio'
          minus
          select num_aula, tipo_aula
            from occr_lezione
            where to_char(Data_inizio_occr_lezione,'hh24:mi') = '12:30'
            and Nome_sede = 'Centro Direzionale'
            and Giorno_lezione = 2
        )
        USING(num_aula,tipo_aula)
)
SELECT *
FROM x
WHERE x.seq = 1;

ROWNUM关键字的行为与您的想法不同,请参阅this article about rownum

要提供更多详细信息,请在为结果集指定任何订单之前分配ROWNUM

如果您确实希望使用ROWNUM关键字获得正确的结果,那么您可以使用首先排序的子查询来实现此目的,然后将rownum生成到实际排序的结果集。但是,我更喜欢第一种方法,因为在我看来它更具可读性,但你可以自由选择这种方法。

SELECT *
FROM (SELECT num_aula, 
           tipo_aula, min(abs(capienza-1)) score
        FROM aula
        JOIN (
            select num_aula, tipo_aula
            from aula
            where tipo_aula = 'Laboratorio'
            minus
                select num_aula, tipo_aula
                from occr_lezione
                where to_char(Data_inizio_occr_lezione,'hh24:mi') = '12:30'
                  and Nome_sede = 'Centro Direzionale'
                  and Giorno_lezione = 2
            ) USING(num_aula,tipo_aula)
        GROUP BY num_aula, tipo_aula
        ORDER BY score asc) x
WHERE x.rownum = 1;

答案 1 :(得分:1)

在进行任何排序之前将rownum分配给该行,因此我怀疑在没有where rownum = 1的情况下删除您的订单并运行将返回:

NUM TIPO_AULA                 SCORE
--- -------------------- ----------
2   Laboratorio                  35
1   Laboratorio                  35

有一篇关于rownum的好文章可以在这里找到: http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html

答案 2 :(得分:1)

我不确定这里的问题是rownum。您使用的是order by score,但这并不能唯一地定义订单,因为有score的重复值。

尝试使用order by score, num以获得稳定的排序,看看是否能解决您的问题。

请注意,缺少稳定排序也会影响row_number(),因此只需切换到row_number()可能无法解决问题 - 除非您包含一个加法字段以使排序稳定。

答案 3 :(得分:1)

SELECT num_aula, tipo_aula, min(abs(capienza-1)) score
FROM aula
JOIN (
        select num_aula, tipo_aula
        from aula
        where tipo_aula = 'Laboratorio'
        minus
        select num_aula, tipo_aula
        from occr_lezione
        where to_char(Data_inizio_occr_lezione,'hh24:mi') = '12:30'
        and Nome_sede = 'Centro Direzionale'
        and Giorno_lezione = 2
     )
USING(num_aula,tipo_aula)
GROUP BY num_aula, tipo_aula
ORDER BY score asc
FETCH FIRST ROW ONLY;

使用FETCH FIRST ROW ONLY会对结果进行排序,然后返回第一行,这样您就不需要再次选择并拥有WHERE ROWNUM = 1

答案 4 :(得分:-2)

如果你这样说:

with t as
(
   select *
   from foo
   order by foo.x
)
select *
from t
where t.rownum = 1
  1. 您尚未在实际查询中通过order by指定订单。 SQL可以按任意顺序自由返回结果集(甚至可以改变从一个执行到另一个执行的顺序)。

  2. 优化器将忽略内部'select'语句中的order by,除非您在内部选择中使用行编号或分区等执行某些操作。

  3. 您假设排序顺序相对于重复值的排序是稳定的。

  4. 所以......你需要写这样的东西:

    with t as
    (
       select *
       from foo
    )
    select *
    from t
    order by foo.x, foo.id
    where t.rownum = 1