Reputation: 532
I have a problem with a query generated by an ORM framework to limit and order the results in the Oracle Database 11.2.0.1.0 64bit Production. The generated select looks like this:
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;
Trying to understand the problem I created the following sandbox:
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;
Executing the select in this example it returns:
id name description 1 DDD-1234 (null) 2 DDD-1234 (null) 3 DDD-1234 (null) 4 DDD-1234 (null)
In my understanding it should return:
id name description 1 AAA-1234 test1 2 BBB-1234 test2 3 CCC-1234 test3 4 DDD-1234 test4
What is wrong? Why is it not returning what I expected it to?
Edited: Removing the ORDER BY clause it returns the expected result. But why?
Edited 2: The execution plan is the following:
---------------------------------------------------------------------------------
| 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)
Upvotes: 0
Views: 1246
Reputation: 62
In the subquery, there is something that seems strange to me:
SELECT this_.* FROM plate **this_**
WHERE this_.id IN
(SELECT DISTINCT this_.id AS y0_ FROM plate **this_** )
ORDER BY this_.name asc
The this_ alias is used twice for 2 different Selects. Maybe this causes something wrong with the results. I am not sure what this_ is pointing to in the order by clause for example. I cannot guarantee this is the reason for your issue but it seems very odd to me.
Upvotes: 1
Reputation: 5950
Very interesting... I found it is the combination of these three elements that causes the wrong results:
WHERE this_.id IN (SELECT...)
ORDER BY
as you pointed out in your EditROWNUM
in the outer selectIf you omit one of the three elements listed here above everything is ok. Don't know what confuses Oracle. To maintain the structure of your query I'd use ROW_NUMBER() in the subquery instead of ROWNUM in the outer Select. This way:
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;
Upvotes: 0