From: Geoff Muldoon on
Hi all,

10.2.x on Linux ...

Is there a "neater"/more efficient way of selecting the maximum value for
a column based on the maximum value of another column. Gods that reads
poorly, I'll try an example ...

SomeTable
ColX ColY ColZ .... MoreCols
A 1 8 ....
A 1 9 ....
A 3 4 ....
A 3 6 ....
.....
B 7 2 ....
B 7 7 ....
B 8 3 ....
B 8 5 ....
.....

I want to get all columns for each distinct value in ColX, but only the
row for the max value of ColY, and the max value of ColZ for that
combination, ie.:

A 3 6 ....
B 8 5 ....

I already have code that returns the correct result, I'm just wondering if
there is a technique to do this which is more effective/efficient.

Current dummy code:
SELECT ColX, ColY, ColZ, ... MoreCols
FROM SomeTable
WHERE (ColX, ColY, ColZ) IN
(SELECT A.ColX, A.ColY, max(B.ColZ)
FROM
(SELECT ColX, max(ColY) ColY
FROM SomeTable
GROUP BY ColX) A,
SomeTable B
WHERE A.ColX = B.ColX
AND A.ColY = B.ColY
GROUP BY A.ColX, A.ColY)
AND <other unrelated where conditions>;

FWIW, the real code is actually querying an Oracle Change Data Capture
subscriber view (ColX is the PK of the source table, ColY is CSCN$ and
ColZ is RSID$), and I want to pick up only the last available change
values in a change window.

Any advice appreciated.

Geoff M
From: Carlos on
On 11 jul, 05:53, Geoff Muldoon <geoff.muld...(a)trap.gmail.com> wrote:
> Hi all,
>
> 10.2.x on Linux ...
>
> Is there a "neater"/more efficient way of selecting the maximum value for
> a column based on the maximum value of another column. Gods that reads
> poorly, I'll try an example ...
>
> SomeTable
> ColX ColY ColZ .... MoreCols
> A 1 8 ....
> A 1 9 ....
> A 3 4 ....
> A 3 6 ....
> ....
> B 7 2 ....
> B 7 7 ....
> B 8 3 ....
> B 8 5 ....
> ....
>
> I want to get all columns for each distinct value in ColX, but only the
> row for the max value of ColY, and the max value of ColZ for that
> combination, ie.:
>
> A 3 6 ....
> B 8 5 ....
>
> I already have code that returns the correct result, I'm just wondering if
> there is a technique to do this which is more effective/efficient.
>
> Current dummy code:
> SELECT ColX, ColY, ColZ, ... MoreCols
> FROM SomeTable
> WHERE (ColX, ColY, ColZ) IN
> (SELECT A.ColX, A.ColY, max(B.ColZ)
> FROM
> (SELECT ColX, max(ColY) ColY
> FROM SomeTable
> GROUP BY ColX) A,
> SomeTable B
> WHERE A.ColX = B.ColX
> AND A.ColY = B.ColY
> GROUP BY A.ColX, A.ColY)
> AND <other unrelated where conditions>;
>
> FWIW, the real code is actually querying an Oracle Change Data Capture
> subscriber view (ColX is the PK of the source table, ColY is CSCN$ and
> ColZ is RSID$), and I want to pick up only the last available change
> values in a change window.
>
> Any advice appreciated.
>
> Geoff M

What about:

SELECT ColX, ColY, ColZ, ... MoreCols
FROM ( select ColX, ColY, ColZ, ... MoreCols, rank () over (partition
by ColX order by colY desc, colZ desc) my_rank from SomeTable ) a
where a.my_rank=1

Not tested.

(No Oracle at hand)

HTH.

Cheers.

Carlos.
From: Mladen Gogala on
On Fri, 11 Jul 2008 13:53:31 +1000, Geoff Muldoon wrote:

> Hi all,
>
> 10.2.x on Linux ...
>
> Is there a "neater"/more efficient way of selecting the maximum value
> for a column based on the maximum value of another column. Gods that
> reads poorly, I'll try an example ...
>
> SomeTable
> ColX ColY ColZ .... MoreCols
> A 1 8 ....
> A 1 9 ....
> A 3 4 ....
> A 3 6 ....
> ....
> B 7 2 ....
> B 7 7 ....
> B 8 3 ....
> B 8 5 ....
> ....
>
> I want to get all columns for each distinct value in ColX, but only the
> row for the max value of ColY, and the max value of ColZ for that
> combination, ie.:
>
> A 3 6 ....
> B 8 5 ....
>
> I already have code that returns the correct result, I'm just wondering
> if there is a technique to do this which is more effective/efficient.
>
> Current dummy code:
> SELECT ColX, ColY, ColZ, ... MoreCols FROM SomeTable
> WHERE (ColX, ColY, ColZ) IN
> (SELECT A.ColX, A.ColY, max(B.ColZ)
> FROM
> (SELECT ColX, max(ColY) ColY
> FROM SomeTable
> GROUP BY ColX) A,
> SomeTable B
> WHERE A.ColX = B.ColX
> AND A.ColY = B.ColY
> GROUP BY A.ColX, A.ColY)
> AND <other unrelated where conditions>;
>
> FWIW, the real code is actually querying an Oracle Change Data Capture
> subscriber view (ColX is the PK of the source table, ColY is CSCN$ and
> ColZ is RSID$), and I want to pick up only the last available change
> values in a change window.
>
> Any advice appreciated.
>
> Geoff M

My advice would be to re-examine your data model instead of looking for
the Mad Max function.

--
Mladen Gogala
http://mgogala.freehostia.com
From: Charles Hooper on
On Jul 10, 11:53 pm, Geoff Muldoon <geoff.muld...(a)trap.gmail.com>
wrote:
> Hi all,
>
> 10.2.x on Linux ...
>
> Is there a "neater"/more efficient way of selecting the maximum value for
> a column based on the maximum value of another column.  Gods that reads
> poorly, I'll try an example ...
>
> SomeTable
> ColX   ColY   ColZ  .... MoreCols
> A      1      8     ....
> A      1      9     ....
> A      3      4     ....
> A      3      6     ....
> ....
> B      7      2     ....
> B      7      7     ....
> B      8      3     ....
> B      8      5     ....
> ....
>
> I want to get all columns for each distinct value in ColX, but only the
> row for the max value of ColY, and the max value of ColZ for that
> combination, ie.:
>
> A      3      6     ....
> B      8      5     ....
(Snip)
> Any advice appreciated.
>
> Geoff M

Let's try a couple tests. First the DDL and DML for the tests:
CREATE TABLE T1(
COLX VARCHAR2(5),
COLY NUMBER(5),
COLZ NUMBER(5));

INSERT INTO T1 VALUES ('A',1,8);
INSERT INTO T1 VALUES ('A',1,9);
INSERT INTO T1 VALUES ('A',3,4);
INSERT INTO T1 VALUES ('A',3,6);
INSERT INTO T1 VALUES ('B',7,2);
INSERT INTO T1 VALUES ('B',7,7);
INSERT INTO T1 VALUES ('B',8,3);
INSERT INTO T1 VALUES ('B',8,5);

Now the first test to see what happens with the MAX analytical
function:
SELECT
COLX,
MAX(COLY) OVER (PARTITION BY COLX) COLY,
COLZ
FROM
T1;

COLX COLY COLZ
----- ---------- ----------
A 3 8
A 3 9
A 3 4
A 3 6
B 8 2
B 8 7
B 8 3
B 8 5

The above looks interesting, let's see if it will work by sliding the
above into an inline view and then picking up the maximum value for
COLZ:
SELECT DISTINCT
COLX,
COLY,
MAX(COLZ) OVER (PARTITION BY COLX, COLY) COLZ
FROM
(SELECT
COLX,
MAX(COLY) OVER (PARTITION BY COLX) COLY,
COLZ
FROM
T1);

COLX COLY COLZ
----- ---------- ----------
B 8 7
A 3 9

Slight problem with COLZ in the above. Let's try again, this time
partitioning by two columns from the start:
SELECT
COLX,
COLY OLD_COLY,
MAX(COLY) OVER (PARTITION BY COLX) COLY,
MAX(COLZ) OVER (PARTITION BY COLX, COLY) COLZ
FROM
T1;

COLX OLD_COLY COLY COLZ
----- ---------- ---------- ----------
A 1 3 9
A 1 3 9
A 3 3 6
A 3 3 6
B 7 8 7
B 7 8 7
B 8 8 5
B 8 8 5

Now to slide the above into an inline view and pick out only those
rows where COLZ originally existed within a matching COLY value:
SELECT DISTINCT
COLX,
COLY,
COLZ
FROM
(SELECT
COLX,
COLY OLD_COLY,
MAX(COLY) OVER (PARTITION BY COLX) COLY,
MAX(COLZ) OVER (PARTITION BY COLX, COLY) COLZ
FROM
T1)
WHERE
OLD_COLY=COLY;

COLX COLY COLZ
----- ---------- ----------
B 8 5
A 3 6


Let's test the output of the SQL statement provided by Carlos with my
test table:
SELECT ColX, ColY, ColZ
FROM ( select ColX, ColY, ColZ, rank () over (partition
by ColX order by colY desc, colZ desc) my_rank from T1 ) a
where a.my_rank=1;

COLX COLY COLZ
----- ---------- ----------
A 3 6
B 8 5

It looks like the SQL that Carlos provided works with the sample data
also.

Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc.
From: Mladen Gogala on
On Fri, 11 Jul 2008 04:42:20 -0700, Charles Hooper wrote:

> SELECT DISTINCT
> COLX,
> COLY,
> COLZ
> FROM
> (SELECT
> COLX,
> COLY OLD_COLY,
> MAX(COLY) OVER (PARTITION BY COLX) COLY, MAX(COLZ) OVER (PARTITION
> BY COLX, COLY) COLZ
> FROM
> T1)
> WHERE
> OLD_COLY=COLY;

And, if T1 has few thousand rows, it's going to be full table scan,
window sort and sort distinct, in that order. In other words, the
resource consumption will just explode. As this is obviously a report,
materialized view looks like the only reasonable solution. This is a
sort of "mad max" query.



--
http://mgogala.freehostia.com