dbTalk Databases Forums  

selecting a column according to a minimum

comp.databases.oracle comp.databases.oracle


Discuss selecting a column according to a minimum in the comp.databases.oracle forum.



Reply
 
Thread Tools Display Modes
  #1  
Old   
Agoston Bejo
 
Posts: n/a

Default selecting a column according to a minimum - 10-18-2004 , 06:50 AM






Take a look at the following example:

table T(i INTEGER, j INTEGER)

I want to get the value of i where j is minimal and some conditions apply.

(1)
SELECT i FROM T
WHERE [condition]
AND j
IN (SELECT min(j) FROM T WHERE [condition])

The best would be if such a syntax was allowed (which it isn't):
SELECT i, min(j) FROM T WHERE [condition]

How can I rewrite the SELECT statement in (1) such that [condition] doesn't
have to be typed in twice? Or how can I achieve the same thing in some other
way? (I am open to other solutions as well as long as they are inside the
limits of Oracle PL/SQL.)



Reply With Quote
  #2  
Old   
Serge Rielau
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-18-2004 , 08:06 AM






SELECT i FROM
(SELECT MIN(j) OVER() as minj, j , i FROM T
WHERE [condition]) AS X WHERE minj = j

Whether that is faster or slower than your original depends on the
Oracle's internals which I don't know.

Cheers
Serge

Reply With Quote
  #3  
Old   
Turkbear
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-18-2004 , 08:43 AM



"Agoston Bejo" <gusz1 (AT) freemail (DOT) hu> wrote:

Quote:
Take a look at the following example:

table T(i INTEGER, j INTEGER)

I want to get the value of i where j is minimal and some conditions apply.

(1)
SELECT i FROM T
WHERE [condition]
AND j
IN (SELECT min(j) FROM T WHERE [condition])

The best would be if such a syntax was allowed (which it isn't):
SELECT i, min(j) FROM T WHERE [condition]

How can I rewrite the SELECT statement in (1) such that [condition] doesn't
have to be typed in twice? Or how can I achieve the same thing in some other
way? (I am open to other solutions as well as long as they are inside the
limits of Oracle PL/SQL.)

Will this do what you want?

Select i.min(j) from T
where [condition].
GROUP BY i;






Reply With Quote
  #4  
Old   
Turkbear
 
Posts: n/a

Default Re: selecting a column according to a minimum - Correction - 10-18-2004 , 08:49 AM



Turkbear <john.g (AT) dot (DOT) spamfree.com> wrote:

Quote:
"Agoston Bejo" <gusz1 (AT) freemail (DOT) hu> wrote:

Take a look at the following example:

table T(i INTEGER, j INTEGER)

I want to get the value of i where j is minimal and some conditions apply.

(1)
SELECT i FROM T
WHERE [condition]
AND j
IN (SELECT min(j) FROM T WHERE [condition])

The best would be if such a syntax was allowed (which it isn't):
SELECT i, min(j) FROM T WHERE [condition]

How can I rewrite the SELECT statement in (1) such that [condition] doesn't
have to be typed in twice? Or how can I achieve the same thing in some other
way? (I am open to other solutions as well as long as they are inside the
limits of Oracle PL/SQL.)

Will this do what you want?

Select i.min(j) from T
where [condition].
GROUP BY i;



No it won't I now realize..It will return all i and, for each i, the Min(j) - the OP wants only those i that have as j the
min(j).
value.

Sorry...





Reply With Quote
  #5  
Old   
Agoston Bejo
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-19-2004 , 04:12 AM



Actually, here is what I could come up with:

select i from
(SELECT i, j FROM T WHERE [condition] ORDER BY j )
WHERE ROWNUM = 1

Is this very inefficient?

"Agoston Bejo" <gusz1 (AT) freemail (DOT) hu> wrote

Quote:
Take a look at the following example:

table T(i INTEGER, j INTEGER)

I want to get the value of i where j is minimal and some conditions apply.

(1)
SELECT i FROM T
WHERE [condition]
AND j
IN (SELECT min(j) FROM T WHERE [condition])

The best would be if such a syntax was allowed (which it isn't):
SELECT i, min(j) FROM T WHERE [condition]

How can I rewrite the SELECT statement in (1) such that [condition]
doesn't
have to be typed in twice? Or how can I achieve the same thing in some
other
way? (I am open to other solutions as well as long as they are inside the
limits of Oracle PL/SQL.)





Reply With Quote
  #6  
Old   
Martin Dachselt
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-20-2004 , 05:18 AM



"Agoston Bejo" <gusz1 (AT) freemail (DOT) hu> wrote

Quote:
Actually, here is what I could come up with:

select i from
(SELECT i, j FROM T WHERE [condition] ORDER BY j )
WHERE ROWNUM = 1

Is this very inefficient?

According to oracle doc the rownum is computed before the "order by" statement
is applied.

Perhaps better:

select i,j from
(select i,j,row_number() over (order by j) rn)
where rn=1;

Bye
Martin


Reply With Quote
  #7  
Old   
Holger Baer
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-20-2004 , 06:01 AM



Martin Dachselt wrote:
Quote:
"Agoston Bejo" <gusz1 (AT) freemail (DOT) hu> wrote


Actually, here is what I could come up with:

select i from
(SELECT i, j FROM T WHERE [condition] ORDER BY j )
WHERE ROWNUM = 1

Is this very inefficient?



According to oracle doc the rownum is computed before the "order by" statement
is applied.
Not if the order by is in a inline view:

baer@DEMO10G>create table test (i integer, j integer);

Table created.

baer@DEMO10G>begin
2 for x in 1..100 loop
3 insert into test values (x, 100-x);
4 end loop;
5 end;
6 /

PL/SQL procedure successfully completed.

baer@DEMO10G>commit;

Commit complete.

baer@DEMO10G>select i from (select i,j from test order by j)
2 where rownum=1;

I
----------
100

baer@DEMO10G>select min (j) from test;

MIN(J)
----------
0

baer@DEMO10G>select i from test where j=0;

I
----------
100


Quote:
Perhaps better:

select i,j from
(select i,j,row_number() over (order by j) rn)
where rn=1;

Not without additional input for the optimizer:

baer@DEMO10G>select i,j from
2 (select i,j,row_number() over (order by j) rn from test)
3* where rn=1


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=100 Bytes=390
0)

1 0 VIEW (Cost=3 Card=100 Bytes=3900)
2 1 WINDOW (SORT PUSHED RANK) (Cost=3 Card=100 Bytes=500)
3 2 TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=2 Card=100
Bytes=500)




baer@DEMO10G>select i from (select i,j from test order by j) where rownum=1;

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=13)
1 0 COUNT (STOPKEY)
2 1 VIEW (Cost=3 Card=100 Bytes=1300)
3 2 SORT (ORDER BY STOPKEY) (Cost=3 Card=100 Bytes=500)
4 3 TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=2 Card=1
00 Bytes=500)




Note the appearence of STOPKEY: The optimizer nows that with rownum=XY
you will likely not take all of the result. This might lead the optimizer
to favour a first_rows plan.

Regards,

Holger


Reply With Quote
  #8  
Old   
Martin Dachselt
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-20-2004 , 12:37 PM



Quote:
baer@DEMO10G>select i from test where j=0;

I
----------
100
Yeah, you are right.
Quote:

Note the appearence of STOPKEY: The optimizer nows that with rownum=XY
you will likely not take all of the result. This might lead the optimizer
to favour a first_rows plan.

Strange: costs and execution time seems bo be equal, even for big
tables.
I thought the optimizer is guessing disk and cpu usage.

select * from (
select id,to_char(datetime,'yyyy-mm-dd hh24:mi:ss') from fdetailrecord
order by id
) where rownum < 5;

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=82560 Card=4 Bytes=2
10937680)

1 0 COUNT (STOPKEY)
2 1 VIEW (Cost=82560 Card=8789070 Bytes=210937680)
3 2 SORT (ORDER BY STOPKEY) (Cost=82560 Card=8789070 Bytes
=123046980)

4 3 TABLE ACCESS (FULL) OF 'FDETAILRECORD' (Cost=61711 C
ard=8789070 Bytes=123046980)


select * from (
select id,to_char(datetime,'yyyy-mm-dd hh24:mi:ss'),row_number() over
(order by id) rn from fdetailrecord
) where rn < 5;

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=82560 Card=8789070 B
ytes=325195590)

1 0 VIEW (Cost=82560 Card=8789070 Bytes=325195590)
2 1 WINDOW (SORT PUSHED RANK) (Cost=82560 Card=8789070 Bytes
=123046980)

3 2 TABLE ACCESS (FULL) OF 'FDETAILRECORD' (Cost=61711 Car
d=8789070 Bytes=123046980)


One advantage of the solution with analytic functions, is that you can
do:
select * from (
select id,to_char(datetime,'yyyy-mm-dd hh24:mi:ss'),row_number() over
(order by id) rn from fdetailrecord
) where rn between 5 and 10;

Cu

Martin


Reply With Quote
  #9  
Old   
Holger Baer
 
Posts: n/a

Default Re: selecting a column according to a minimum - 10-20-2004 , 03:21 PM



Martin Dachselt wrote:
[..]

Quote:
Strange: costs and execution time seems bo be equal, even for big
tables.
Not in my tests. The difference was small, but analytics always came last
(same table as in my previous post, but this time with 10 million rows).
The runtime was about 6.5 s for the rownum solution and 7s for the analytics
solution.

Quote:
I thought the optimizer is guessing disk and cpu usage.

But they won't make any difference. A full scan is a fullscan, no matter
what you try. But note the difference in the cardinality and bytes between
the your plans. With rownum, the plan is expected to return exactly the
number of rows you asked for. With analytics, oracle cannot now how much
data you're going to retrieve, so it's pessimistic and expects the worst.

Quote:
One advantage of the solution with analytic functions, is that you can
do:
select * from (
select id,to_char(datetime,'yyyy-mm-dd hh24:mi:ss'),row_number() over
(order by id) rn from fdetailrecord
) where rn between 5 and 10;
But not really what the OP asked for, is it? And this one is equivalent
in every respect (except that it's slightly faster on my machine):

select * from (
select i, rownum rn from (select i,j from test order by j)
where rownum<= 10)
where rn between 5 and 10
/

To return to the original question:


select i from test where i between 10 and 15
and j in (select min(j) from test where i between 10 and 15)

is a working example of what the OP regarded as not possible (at least in 10g it works).
And with proper indexes in place this is pretty fast, too.

Perhaps we can get the OP to explain his problem better?

Regards,
Holger


Reply With Quote
Reply




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.3
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.