rownum语句的错误结果

时间:2018-04-25 17:09:32

标签: sql oracle oracle11g

我在使用Hibernate生成的SQL语句时遇到了一些麻烦。我想让所有用户在给定的时间范围内或特定的一天内过生日。虽然特定日期的声明工作正常,但另一个只返回前n个用户,其中n是正确用户的数量。

考虑这些数据:

ID     name      birthdate
1      firstUser 12.07.1990
2      user1     25.04.2007
3      user2     15.05.1992
4      user3     01.04.1988

首先是特定日期的生成语句:

select
    * 
from
    ( select
        distinct *
    from
        USERS user0_ 
    where
        calculateNextBirthday(user0_.birthDate) = TO_DATE('25.04.2018', 'dd.MM.yyyy')
    order by
        user0_.id asc ) 
where
    rownum <= ?; // This will be the row count of this statement with the same where clause, i.e. 1 if there is only 1 matching user

正如我所说,这句话会返回正确的用户(user1,ID为2)。

与之间的相同陈述:

select
    * 
from
    ( select
        distinct *
    from
        USERS user0_ 
    where
        calculateNextBirthday(user0_.birthDate) between TO_DATE('01.04.2018', 'dd.MM.yyyy') and TO_DATE('30.04.2018', 'dd.MM.yyyy')
    order by
        user0_.id asc ) 
where
    rownum <= ?; // This will be the row count of this statement with the same where clause, i.e. 1 if there is only 1 matching user

此声明有一种奇怪的行为。如果我执行内部select语句,结果将包含正确的用户(user1)。但是执行整个语句它将返回第一个用户(firstUser ID为1)。像这样更改日期:

select
    * 
from
    ( select
        distinct *
    from
        USERS user0_ 
    where
        calculateNextBirthday(user0_.birthDate) between TO_DATE('01.04.2018', 'dd.MM.yyyy') and TO_DATE('30.06.2018', 'dd.MM.yyyy')
    order by
        user0_.id asc ) 
where
    rownum <= ?; // This will be the row count of this statement with the same where clause, i.e. 1 if there is only 1 matching user

将返回前两个用户(firstUseruser1),因为有两个匹配的用户(user1user2

如果我从外部语句中删除rownum,它只返回正确的用户(下面的示例返回user1)。

select
    * 
from
    ( select
        distinct *
    from
        USERS user0_ 
    where
        calculateNextBirthday(user0_.birthDate) between TO_DATE('01.04.2018', 'dd.MM.yyyy') and TO_DATE('30.04.2018', 'dd.MM.yyyy')
    order by
        user0_.id asc ) 

所以我不知道Oracle在哪里获得第一个用户条目。

我在这里做错了什么,或Oracle Oracle数据库10g快捷版10.2.0.1.0中是否有错误?

2 个答案:

答案 0 :(得分:1)

似乎适合我(11g)。我不会使用你的calculateNextBirthday函数:

SQL> drop table t_users
Table dropped.
SQL> create table t_users
(
id number,
name varchar2(100),
birthdate date
)
Table created.
SQL> insert into t_users (id,name,birthdate) values (1,'firstUser',to_date('12.07.1990','DD.MM.YYYY'))
1 row created.
SQL> insert into t_users (id,name,birthdate) values (2,'user1',to_date('25.04.2007','DD.MM.YYYY'))
1 row created.
SQL> insert into t_users (id,name,birthdate) values (3,'user2',to_date('15.05.1992','DD.MM.YYYY'))
1 row created.
SQL> insert into t_users (id,name,birthdate) values (4,'user3',to_date('01.04.1988','DD.MM.YYYY'))
1 row created.
SQL> commit
Commit complete.
SQL> select
    * 
from
    ( select
        distinct *
    from
        t_users user0_ 
    where
        to_date( to_char(birthdate, 'DD.MM') || '.' || to_char(sysdate, 'YYYY'), 'DD.MM.YYYY' ) between TO_DATE('01.04.2018', 'dd.MM.yyyy') and TO_DATE('30.04.2018', 'dd.MM.yyyy')
    order by
        user0_.id asc ) 
where
    rownum <= 2

        ID
----------
NAME                                                                            
--------------------------------------------------------------------------------
BIRTHDATE
---------
         2
user1                                                                           
25-APR-07

         4
user3                                                                           
01-APR-88


2 rows selected.

答案 1 :(得分:0)

在这种情况下你不能依赖rownum,因为order by在内部选择中。 Rownum正在确定之前,因此也是一般的。一般来说,依靠rownum并不是一个好习惯。

有一点需要注意,我知道Oracle SQL并且我并不熟悉Hibernate,我的建议是以下

我会考虑用你需要的信息创建一个视图,看看Hibernate是否能更好地处理它,否则我会试着用一个只使用内部选择的Hibernate生成的SQL语句来覆盖它,因为它没有Oracle有理由使用outer语句包装该选择。