2016-01-21 2 views
0

У меня возникла проблема с запросом, сгенерированным инфраструктурой ORM, чтобы ограничить и упорядочить результаты в Oracle Database 11.2.0.1.0 64bit Production. Сформированные выберите выглядит следующим образом:Неверные результаты запроса с ORDER BY и ROWNUM

SELECT * 
FROM 
    (SELECT this_.* 
    FROM plate this_ 
    WHERE this_.id IN 
     (SELECT DISTINCT this_.id AS y0_ FROM plate this_) 
    ORDER BY this_.name asc) 
WHERE rownum <= 10; 

Пытаясь понять проблему, которую я создал следующую песочницу:

create table plate (id integer primary key, 
        name varchar2(30), 
        description varchar2(255)); 

insert into plate values (1, 'AAA-1234', 'test1'); 
insert into plate values (2, 'BBB-1234', 'test2'); 
insert into plate values (3, 'CCC-1234', 'test3'); 
insert into plate values (4, 'DDD-1234', 'test4'); 
commit; 

Выполнение операции выбора в этом примере он возвращает:

id name  description 
1 DDD-1234 (null) 
2 DDD-1234 (null) 
3 DDD-1234 (null) 
4 DDD-1234 (null) 

В моей понимая, что он должен вернуться:

id name  description 
1 AAA-1234 test1 
2 BBB-1234 test2 
3 CCC-1234 test3 
4 DDD-1234 test4 

Что не так? Почему он не возвращает то, что я ожидал?

Отредактировано: Снятие предложения ORDER BY возвращает ожидаемый результат. Но почему?

Edited 2: План выполнения заключается в следующем:

--------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |  |  |  |  4 (100)|   | 
|* 1 | COUNT STOPKEY   |  |  |  |   |   | 
| 2 | VIEW     |  |  4 | 636 |  4 (25)| 00:00:01 | 
|* 3 | SORT ORDER BY STOPKEY|  |  4 | 636 |  4 (25)| 00:00:01 | 
| 4 |  TABLE ACCESS FULL | PLATE |  4 | 636 |  3 (0)| 00:00:01 | 
--------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter(ROWNUM<=10) 
    3 - filter(ROWNUM<=10) 

Note 
----- 
    - dynamic sampling used for this statement (level=2) 
+0

Для меня запрос возвращает все четыре различных значения таблицы PLATES. Здесь нет ошибки. Следует сказать, что запрос имеет избыточную часть: «id IN (SELECT DISTINCT this_.id AS y0_ FROM plate this_)», который в этом случае ничего не делает. – diziaq

+0

Кажется, что-то вроде ошибки в CBO, что вызывает неправильную переписку вашего запроса. Просто протестированный в 11.2.0.2.0 XE, он работает хорошо. Если бы вы могли опубликовать план выполнения, это было бы полезно. – Aleksej

+0

@Aleksej План выполнения добавлен на вопрос. – Willian

ответ

1

В подзапроса, есть что-то, что мне кажется странным:

SELECT this_.* FROM plate **this_** 
WHERE this_.id IN 
(SELECT DISTINCT this_.id AS y0_ FROM plate **this_**) 
ORDER BY this_.name asc 

this_ псевдоним используется дважды для двух разных вариантов. Возможно, это приводит к неправильным результатам. Я не уверен, что это означает, например, в предложении order by. Я не могу гарантировать, что это причина вашей проблемы, но мне кажется очень странным.

+0

Даже если я изменяю запрос на 'SELECT * FROM (SELECT t1. * FROM plate t1 WHERE t1.id IN (SELECT DISTINCT t2.id AS y0_ FROM plate t2) ORDER BY t1.name) WHERE rownum <= 10; 'результат по-прежнему ошибочен. – Willian

0

Очень интересно ... Я нашел это сочетание этих трех элементов, что вызывает неправильные результаты:

  1. WHERE this_.id IN (SELECT...)
  2. ORDER BY как вы отметили в вашем Edit
  3. ROWNUM в наружной выберите

Если вы опустите один из трех перечисленных здесь элементов, все в порядке. Не знаю, что смущает Oracle. Чтобы сохранить структуру вашего запроса, я бы использовал ROW_NUMBER() в подзапросе вместо ROWNUM во внешнем Select. Таким образом:

SELECT id, name, description 
FROM 
    (SELECT this_.*, ROW_NUMBER() OVER(ORDER BY this_.name ASC) AS RN 
    FROM plate this_ 
    WHERE this_.id IN 
     (SELECT DISTINCT this_.id AS y0_ FROM plate this_) 
    ) 
WHERE rn <= 10 
ORDER BY rn asc; 
+0

Хорошее решение, дает правильный результат, но несколько затрудняет заставить ORM генерировать такой запрос (ORM автоматически генерирует часть «rownum', чтобы ограничить количество результатов). – Willian

+0

@Willian Ну, если вы не можете изменить SQL, сгенерированный ORM, я вижу только два варианта: (1) убедить ORM генерировать лучший SQL (элемент 1 в моем списке здесь выше 'where this_.id in (select. ..' бесполезно или (2) убедить Oracle исправить то, что кажется ошибкой ... Удачи :-) – mauro

Смежные вопросы