I have two tables. Table1
:
| ID1 | ID2 | ID3 | ID4 |
|-----+-----+-----+-----|
| 200 | 125 | 300 | 201 |
| 206 | 128 | 650 | 261 |
| 230 | 543 | 989 | 403 |
and Table2
:
| ID1 | ID2 | ID3 | ID4 | Date | Cost |
|-----+-----+-----+-----+--------+------|
| 200 | 125 | 300 | 201 | 1/1/19 | 0.32 |
| 200 | 125 | 300 | 201 | 1/1/19 | 0.33 |
| 200 | 125 | 300 | 201 | 1/1/19 | 0.34 |
| 200 | 125 | 300 | 201 | 1/2/13 | 0.00 |
| 200 | 125 | 300 | 201 | 9/5/05 | 0.01 |
I am trying to Join
Table1
to Table2
while filtering the outputs so only one row where date
is at its maximum for those classifications are displayed and the average cost
at that maximum date is also displayed. Here is my current code:
SELECT t1.ID1, t1.ID2, t1.ID3, t1.ID4, maxDate, avgCost
FROM Table1 t1
JOIN ( SELECT ID1, ID2, ID3, ID4, MAX(Date) as maxDate, AVG(Cost) as avgCost
FROM Table2 t2
GROUP BY ID1, ID2, ID3, ID4 ) t2
ON t2.ID1 = t1.ID1
AND t2.ID2 = t1.ID2
AND t2.ID3 = t1.ID3
AND t2.ID4 = t1.ID4
With the example data given above, my result looks like this:
| ID1 | ID2 | ID3 | ID4 | MaxDate | AvgCost |
|-----+-----+-----+-----+-----------+---------|
| 200 | 125 | 300 | 201 | 1/1/19 | 0.20 |
When it should just be looking like this
| ID1 | ID2 | ID3 | ID4 | MaxDate | AvgCost |
|-----+-----+-----+-----+-----------+---------|
| 200 | 125 | 300 | 201 | 1/1/19 | 0.33 |
The average cost is including values where date
is not at its maximum. I’m assuming this is due to AVG(cost)
being executed before Table2
is filtered with MAX(Date)
. Here’s what I’ve tried:
SELECT t1.ID1, t1.ID2, t1.ID3, t1.ID4, maxDate, avgCost
FROM Table1 t1
JOIN ( SELECT ID1, ID2, ID3, ID4, MAX(Date) as maxDate, AVG(Cost) as avgCost
FROM Table2 t2
GROUP BY ID1, ID2, ID3, ID4 ) t2
ON t2.ID1 = t1.ID1
AND t2.ID2 = t1.ID2
AND t2.ID3 = t1.ID3
AND t2.ID4 = t1.ID4
WHERE maxDate = (SELECT MAX(Date) from Table2);
and
SELECT t1.ID1, t1.ID2, t1.ID3, t1.ID4, maxDate, avgCost
FROM Table1 t1
JOIN ( SELECT ID1, ID2, ID3, ID4, MAX(Date) as maxDate, AVG(Cost) as avgCost
FROM Table2 t2
GROUP BY ID1, ID2, ID3, ID4 ) t2
ON t2.ID1 = t1.ID1
AND t2.ID2 = t1.ID2
AND t2.ID3 = t1.ID3
AND t2.ID4 = t1.ID4
WHERE maxDate = (SELECT MAX(Date) from Table2 GROUP BY ID1, ID2, ID3, ID4);
The first gives no results and the second results in an error, ORA-01427: single-row subquery returns more than one row
. The rest of what I’ve tried is basically variations of the above, but I’m still not getting the results expected. I’m not sure how to make the AVG
function perform only where Date
is at its max…
Advertisement
Answer
Your definition of t2
looks like this:
( SELECT ID1, ID2, ID3, ID4, MAX(Date) as maxDate, AVG(Cost) as avgCost
FROM Table2 t2
GROUP BY ID1, ID2, ID3, ID4 ) t2
Instead, to compute the average only over the most recent date, it should use a different aggregate function – the LAST
function, like so:
( SELECT ID1, ID2, ID3, ID4, MAX(Date) as maxDate,
AVG(Cost) KEEP (DENSE_RANK LAST ORDER BY Date) as avgCost
FROM Table2 t2
GROUP BY ID1, ID2, ID3, ID4 ) t2