Неправильный результат из заявления с rownum - PullRequest
0 голосов
/ 25 апреля 2018

У меня возникли проблемы с сгенерированным оператором SQL из Hibernate.Я хочу получить всех пользователей с их днем ​​рождения в течение определенного периода времени или в определенный день.В то время как оператор для определенного дня работает нормально, другой просто возвращает первых 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 с идентификатором 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

У этого персонажа странное поведение.Если я выполню внутренний оператор выбора, результат будет содержать правильных пользователей (user1).Но, выполнив весь оператор, он вернет первого пользователя (firstUser с идентификатором 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

вернет первых двух пользователей (firstUser и user1), потому что есть два подходящих пользователя (user1 и user2)

И если я удаляю 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 Database 10g Express Edition Release 10.2.0.10,0

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Кажется, работает на меня (11 г).Я не использую вашу функцию 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.
0 голосов
/ 25 апреля 2018

Вы не можете полагаться на rownum в этой ситуации, потому что заказ находится во внутреннем выборе.Rownum определяется до и, следовательно, переопределяет порядок по.Не стоит полагаться на rownum в целом.

С учетом того, что я знаю Oracle SQL и по своей сути не знаком с Hibernate, я предлагаю следующее: :

Я хотел бы рассмотреть создание представления с информацией, которую вынужно и посмотреть, справится ли Hibernate с этим лучше, иначе я бы попытался переопределить сгенерированный оператор Hibernate SQL с помощью оператора, который просто использует внутренний выбор, потому что у Oracle нет причины переносить этот выбор с помощью внешнего оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...