How to use multiple max Function in SQL select with left join - sql

Suppose I have the following three tables:
Table1:
ID
Value_1
11
abc
22
def
33
xyz
Table2:
ID
Date_1
11
12-Mar-22
11
01-Jan-23
22
19-Dec-22
22
07-Feb-23
33
07-Mar-22
Table3:
ID
Length_1
11
574
11
1029
22
9220
33
1093
33
876
Now, I need an SQL query that would select each ID with Max Lenth_1 and Max Date_1.
Desired output:
ID
Value_1
Date_1
Length_1
11
abc
01-Jan-23
1029
22
def
07-Feb-23
9220
33
xyz
07-Mar-22
1093
I have used max() fuction to achieve this with left join between 2 tables together, however struggling when I have to use Max () twice with 3 tables. I am relatively new to SQL.
SQL Select Max(Date) out of rows with Duplicate Id
I tried this for two tables

Aggregate before you join the tables:
SELECT t1.id,
t1.value_1,
t2.date_1,
t3.length_1
FROM table1 t1
INNER JOIN (
SELECT id,
MAX(date_1) AS date_1
FROM table2
GROUP BY id
) t2
ON (t1.id = t2.id)
INNER JOIN (
SELECT id,
MAX(length_1) AS length_1
FROM table3
GROUP BY id
) t3
ON (t1.id = t3.id)
Which, for the sample data:
CREATE TABLE Table1 (ID, Value_1) AS
SELECT 11, 'abc' FROM DUAL UNION ALL
SELECT 22, 'def' FROM DUAL UNION ALL
SELECT 33, 'xyz' FROM DUAL;
CREATE TABLE Table2 (ID, Date_1) AS
SELECT 11, DATE '2022-03-12' FROM DUAL UNION ALL
SELECT 11, DATE '2023-01-01' FROM DUAL UNION ALL
SELECT 22, DATE '2022-12-19' FROM DUAL UNION ALL
SELECT 22, DATE '2023-02-07' FROM DUAL UNION ALL
SELECT 33, DATE '2022-03-07' FROM DUAL;
CREATE TABLE Table3 (ID, Length_1) AS
SELECT 11, 574 FROM DUAL UNION ALL
SELECT 11, 1029 FROM DUAL UNION ALL
SELECT 22, 9220 FROM DUAL UNION ALL
SELECT 33, 1093 FROM DUAL UNION ALL
SELECT 33, 876 FROM DUAL;
Outputs:
ID
VALUE_1
DATE_1
LENGTH_1
11
abc
2023-01-01 00:00:00
1029
22
def
2023-02-07 00:00:00
9220
33
xyz
2022-03-07 00:00:00
1093
fiddle

One option is to use subqueries selecting max values from tables 2 and 3:
Select t1.ID, t1.VALUE_1,
(Select Max(DATE_1) From Table2 Where ID = t1.ID) "DATE_1",
(Select Max(LENGTH_1) From Table3 Where ID = t1.ID) "LENGTH_1"
From Table1 t1
Order By t1.ID
... another one is to use analytic function with distinct keyword but it could be performance costly with big datasets:
Select DISTINCT
t1.ID, t1.VALUE_1, Max(t2.DATE_1) OVER(Partition By t1.ID) "DATE_1", Max(t3.LENGTH_1) OVER(Partition By t1.ID) "LENGTH_1"
From Table1 t1
Inner Join Table2 t2 ON(t2.ID = t1.ID)
Inner Join Table3 t3 ON(t3.ID = t1.ID)
Order By t1.ID
... both with your sample data:
WITH
Table1 (ID, VALUE_1) AS
(
Select 11, 'abc' From Dual Union All
Select 22, 'def' From Dual Union All
Select 33, 'xyz' From Dual
),
Table2 (ID, DATE_1) AS
(
Select 11, To_Date('2022-03-12', 'yyyy-mm-dd') From Dual Union All
Select 11, To_Date('2023-01-01', 'yyyy-mm-dd') From Dual Union All
Select 22, To_Date('2022-12-19', 'yyyy-mm-dd') From Dual Union All
Select 22, To_Date('2023-02-07', 'yyyy-mm-dd') From Dual Union All
Select 33, To_Date('2022-03-07', 'yyyy-mm-dd') From Dual
),
Table3 (ID, LENGTH_1) AS
(
Select 11, 574 From Dual Union All
Select 11, 1029 From Dual Union All
Select 22, 9220 From Dual Union All
Select 33, 1093 From Dual Union All
Select 33, 876 From Dual
)
results as:
ID VALUE_1 DATE_1 LENGTH_1
---------- ------- --------- ----------
11 abc 01-JAN-23 1029
22 def 07-FEB-23 9220
33 xyz 07-MAR-22 1093

Select t1.id, t1.value1, max(t2.date_1) date_1, max(t3.length_1)t3
from table_1 t1
left join table_2 t2 on t1.id=t2.id
left join table_3 t3 on t1.id=t3.id
group by t1.id, t1.value1
order by 1

Related

SQL query to get both common and and non common data from 2 tables

Hi im looking for a query which will give me both common and non-common data in one query.
Table 2
ID
Assay
1
124
Result
required_missing
required_present
125
124
Based on req_ind column from table 1 , if req_ind is 1 and the same assay is present in table 2 i want to list it as above.
required missing column can have multiple column.
With the data given this gives requested result:
WITH table1 as (
select 1 as ID, 123 as Assay, 0 as req_ind from dual
union all
select 2,124,1 from dual
union all
select 3,125,1 from dual
),
table2 as (
select 1 as ID, 124 as Assay from dual
),
required_missing as (
select
row_number() over (order by table1.Assay) as R,
table1.Assay as required_missing
from table1
left join table2 on table2.Assay = table1.Assay
where table1.req_ind=1 and table2.id is null
),
requires_present as (
select
row_number() over (order by table1.Assay) as R,
table1.Assay as required_present
from table1
left join table2 on table2.Assay = table1.Assay
where table1.req_ind=1 and table2.id is not null
),
results as (
select row_number() over (order by (id)) as r
from table1
)
select rm.required_missing, rp.required_present
from results
left join required_missing rm on rm.R = results.R
left join requires_present rp on rp.R = results.R
where rm.R is not null or rp.R is not null;
output:
REQUIRED_MISSING
REQUIRED_PRESENT
125
124
If you want to have a comma separated list for missing and for present then you can use:
SELECT LISTAGG(CASE WHEN t2.assay IS NULL THEN t1.assay END, ',')
WITHIN GROUP (ORDER BY t1.assay) AS required_missing,
LISTAGG(t2.assay, ',')
WITHIN GROUP (ORDER BY t1.assay) AS required_present
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON (t1.assay = t2.assay)
WHERE t1.req_ind = 1
Which, for the sample data:
CREATE TABLE table1 (id, assay, req_ind) AS
SELECT 1, 123, 0 FROM DUAL UNION ALL
SELECT 2, 124, 1 FROM DUAL UNION ALL
SELECT 3, 125, 1 FROM DUAL UNION ALL
SELECT 4, 126, 1 FROM DUAL UNION ALL
SELECT 5, 127, 1 FROM DUAL;
CREATE TABLE table2 (id, assay) AS
SELECT 1, 124 FROM DUAL UNION ALL
SELECT 2, 127 FROM DUAL;
Outputs:
REQUIRED_MISSING
REQUIRED_PRESENT
125,126
124,127
If you want the output in multiple rows then:
SELECT required_missing,
required_present
FROM (
SELECT NVL2(t2.assay, 'P', 'M') AS status,
ROW_NUMBER() OVER (
PARTITION BY NVL2(t2.assay, 'P', 'M')
ORDER BY t1.assay
) AS rn,
t1.assay
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON (t1.assay = t2.assay)
WHERE t1.req_ind = 1
)
PIVOT (
MAX(assay)
FOR status IN (
'M' AS required_missing,
'P' AS required_present
)
)
Which outputs:
REQUIRED_MISSING
REQUIRED_PRESENT
125
124
126
127
db<>fiddle here

Oracle - how to replace and sum from the output?

I have output of group by as below.
SELECT param2,count(*) FROM table WHERE CALLED='1234' GROUP BY PARAM2
Param2 count(*)
135; 616
135;135; 18
135;135;135; 4
135;135;135;135; 2
135;135;135;135;135;135;27; 15
135;135;135;27; 5
136; 43
136;136; 383
136;136;136; 47
136;136;136;27; 32
Expected: For all the output param2 that includes 135 or 136 should be group by once again such that result should be as below:
Param2 count(*)
135 660
136 505
For the given example, a simple straight-forward solution would do the job. Not sure if this is as general as necessary:
select '135' as "Param2", count(*) from table
where called = '1234' and ';'||param2 like '%;135;%'
union all
select '136' as "Param2", count(*) from table
where called = '1234' and ';'||param2 like '%;136;%'
Try below query,
Keeping my base source as the output you have mentioned ,we can use traditional regular expression to split the row and get distinct values present for param2 and then a sum over it would give the result as expected. I am little skeptical about how the performance will be but you can give it a try.
with sample data:
with table1
as
(
select '135;' param2, 616 cnt from dual union all
select '135;135;', 18 from dual union all
select '135;135;135;', 4 from dual union all
select '135;135;135;135;', 2 from dual union all
select '135;135;135;135;135;135;27;', 15 from dual union all
select '135;135;135;27;', 5 from dual union all
select '136;', 43 from dual union all
select '136;136;', 383 from dual union all
select '136;136;136;', 47 from dual union all
select '136;136;136;27;', 32 from dual
)
select split,sum(cnt) cnt
from
(select distinct t1.*, regexp_substr(param2,'[^;]+', 1, level) split
from table1 t1;
connect by regexp_substr(param2, '[^;]+', 1, level) is not null)
group by split;
So the final query should be ,
with table1
as
(
select param2, count(*) cnt
from table
where called = '1234'
group by param2
)
select split as param2,sum(cnt) cnt
from
(select distinct t1.*, regexp_substr(param2,'[^;]+', 1, level) split
from table1 t1;
connect by regexp_substr(param2, '[^;]+', 1, level) is not null)
group by split;

Oracle listagg - Can I pull data from other table based on the values selected by listagg

I have two tables and want to get data from one table based on the values got from Listtagg in the second table:
T1
ID Name
==============
1 Name1
2 Person2
3 Someone3
4 Mr.4
T2
ID Acct
===============
1 1234
1 5678
2 1234
3 5678
3 8769
4 1234
My listagg query on T2 has returned the following:
Acct Id
====== ========
1234 1,2,4
5678 1,3
I need the result with Names from other table something like:
Acct Id Name
====== ======== ==========
1234 1,2,4 Name1, Person2, Mr.4
5678 1,3 Name1, Someone3
Why would you first aggregate IDs, and then put effort in splitting them to collect NAMEs? Do it immediately. Not that it can't be done (it can, in a relatively simple manner, but - why?!?).
Sample data is from line #1 - 15; query you might need begins at line #16.
SQL> with
2 t1 (id, name) as
3 (select 1, 'Name1' from dual union all
4 select 2, 'Person2' from dual union all
5 select 3, 'Someone3' from dual union all
6 select 4, 'Mr4' from dual
7 ),
8 t2 (id, acct) as
9 (select 1, 1234 from dual union all
10 select 1, 5678 from dual union all
11 select 2, 1234 from dual union all
12 select 3, 5678 from dual union all
13 select 3, 8769 from dual union all
14 select 4, 1234 from dual
15 )
16 select b.acct,
17 listagg(b.id, ', ') within group (order by b.id) id,
18 listagg(a.name, ', ') within group (order by b.id) name
19 from t1 a join t2 b on a.id = b.id
20 group by b.acct;
ACCT ID NAME
---------- ---------- --------------------
1234 1, 2, 4 Name1, Person2, Mr4
5678 1, 3 Name1, Someone3
8769 3 Someone3
SQL>
#Littlefoot's answer is absolutely correct. But just as an addition: don't use listagg if you are going to split those aggregated values. Just use collect() aggregate function to get needed data as a collection.
For example:
select
cast(collect(level) as sys.odcinumberlist) as varray_of_numbers,
cast(collect(level) as ORA_MINING_NUMBER_NT) as nested_table_of_numbers,
cast(collect(sys.ku$_objnum(level)) as sys.KU$_OBJNUMSET) as nested_table_of_objnum
from dual connect by level<=3;
--Result:
VARRAY_OF_NUMBERS NESTED_TABLE_OF_NUMBERS NESTED_TABLE_OF_OBJNUM(OBJ_NUM)
------------------------- ------------------------------ ------------------------------------------------------------
ODCINUMBERLIST(1, 2, 3) ORA_MINING_NUMBER_NT(1, 2, 3) KU$_OBJNUMSET(KU$_OBJNUM(1), KU$_OBJNUM(2), KU$_OBJNUM(3))
Update: This is a query for your tables, as you asked in the comment:
select b.acct,
cast(collect(b.id) as ORA_MINING_NUMBER_NT) as nested_table_of_numbers,
cast(collect(a.name) as ORA_MINING_VARCHAR2_NT) as nested_table_of_varchar2
-- listagg(b.id, ', ') within group (order by b.id) id,
-- listagg(a.name, ', ') within group (order by b.id) name
from t1 a join t2 b on a.id = b.id
group by b.acct;
Full example:
with
t1 (id, name) as
(select 1, 'Name1' from dual union all
select 2, 'Person2' from dual union all
select 3, 'Someone3' from dual union all
select 4, 'Mr4' from dual
),
t2 (id, acct) as
(select 1, 1234 from dual union all
select 1, 5678 from dual union all
select 2, 1234 from dual union all
select 3, 5678 from dual union all
select 3, 8769 from dual union all
select 4, 1234 from dual
)
select b.acct,
cast(collect(b.id) as ORA_MINING_NUMBER_NT) as nested_table_of_numbers,
cast(collect(a.name) as ORA_MINING_VARCHAR2_NT) as nested_table_of_varchar2
-- listagg(b.id, ', ') within group (order by b.id) id,
-- listagg(a.name, ', ') within group (order by b.id) name
from t1 a join t2 b on a.id = b.id
group by b.acct;

If a then b check in where clause

I am performing some data quality checks to identify bad data, I am unable to figure out how I can perform a check-such that the data is accurately mapped based on Value 1 vs Value 2.
I ultimately need to identify all IDs in T1 that have incorrect mapping in T2.I have used the following code but doesn't seem to give desired result. The mapping is not in the database and is a rule based on which the data needs to be entered.
- When value in: Apples,Bananas,Cherries,Pears,Kiwis - then it should be mapped to Fruit
- when value in: Cheese - then Cheese
- when value in: Cashews,Almonds - then Nuts
- when value in: Skittles - then Candy
- when value in: Chocolate - then null
Edit: I have added the desired output.
SELECT t1.id, t2.*
FROM t1,t2,t3
WHERE
t1.id = t2.id
AND (
(t2.value1_id IN (01,04,05,08,09) AND t2.value2_id <> 2)
OR (t2.value1_id = 02 and t2.value2_id <> 3)
OR (t2.value1_id IN (03,10) and t2.value2_id <> 1)
OR (t2.value1_id = 06 AND t2.value2_id <> 4)
OR (t2.value1_id = 07 AND t2.value_id IS NOT NULL)
)
T1
ID
1
2
3
4
5
6
7
T2
T1.ID Value1_ID Value2_ID
1 01 2
1 02 3
1 03 1
2 04 2
2 05 2
2 02 3
2 06 4
2 07
3 08 2
3 02 3
4 09 2
4 10 1
5 02 2
5 10 1
6 04 3
6 10 2
7 07 2
T3
ID Value1
01 Apples
02 Cheese
03 Cashews
04 Bananas
05 Cherries
06 Skittles
07 Chocolate
08 Pears
09 Kiwis
10 Almonds
T4
ID Value2
1 Nuts
2 Fruit
3 Cheese
4 Candy
Desired Output:
T1.ID Value1_ID Value2_ID
5 02 2
6 04 3
6 10 2
7 07 2
T1.ID 5, value1_id 02 is in the desired output as Cheese is mapped to Fruit
T1.ID 6, value1_id 04 - Bananas is mapped to Cheese
T1.ID 6, value1_id 10 - Almonds is mapped to Fruit
T1.ID 7, value1_id 07 - Chocolate is mapped to Fruit when it should be null
One of the problems is that - when looking at T2 - it is not easy to tell whether a "mapping" is correct or not.
When creating the test data for T1 and T2, we have used CHARs for VALUE1_IDs, in order to make the subsequent queries a bit more "readable".
Tables
create table T1( id primary key )
as
select 1 from dual union all
select 2 from dual union all
select 3 from dual ;
create table T2 ( id, value1_id, value2_id )
as
select 1, '01', 2 from dual union all
select 1, '02', 3 from dual union all
select 1, '03', 1 from dual union all
select 2, '04', 2 from dual union all
select 2, '05', 2 from dual union all
select 2, '02', 3 from dual union all
select 2, '06', 4 from dual union all
select 2, '07', null from dual union all
select 3, '08', 2 from dual union all
select 3, '02', 3 from dual union all
select 4, '09', 2 from dual union all
select 4, '10', 1 from dual ;
Refactored query
--
-- find incorrect mappings
--
select t2.*, 'T1 id not valid' as status
from t2
where t2.id not in ( select id from T1 )
union all
select t2.*, 'value1_id <-> value2_id mapping incorrect '
from t1 join t2 on t1.id = t2.id
where
( t2.value1_id in ('01','04','05','08','09') and t2.value2_id <> 2 )
or
( t2.value1_id = '02' and t2.value2_id <> 3 )
or
( t2.value1_id in ('03','10') and t2.value2_id <> 1 )
or
( t2.value1_id = '06' and t2.value2_id <> 4 )
or
( t2.value1_id = '07' and t2.value2_id is null )
;
-- result
ID VALUE1_ID VALUE2_ID STATUS
4 10 1 T1 id not valid
4 09 2 T1 id not valid
2 07 NULL value1_id <-> value2_id mapping incorrect
DBfiddle
ALTERNATIVE
Another possibility may be: create a table, containing all valid mappings, in "human readable" form, and use it to validate the mappings stored in T2. However, use whatever approach you are more comfortable with - as long as you get the correct results. Example (tested w/ Oracle 12c, 18c)
-- in addition to tables T1, T2, T3, and T4: table with correct mappings
create table map( category, product )
as
select 'Fruit', 'Apples' from dual union all
select 'Cheese', 'Cheese' from dual union all
select 'Nuts', 'Cashews' from dual union all
select 'Fruit', 'Bananas' from dual union all
select 'Fruit', 'Cherries' from dual union all
select 'Candy', 'Skittles' from dual union all
select 'Candy', 'Chocolate' from dual union all
select 'Fruit', 'Pears' from dual union all
select 'Fruit', 'Kiwis' from dual union all
select 'Nuts', 'Almonds' from dual;
-- make sure that the entries in the MAP table tie in with T3 and T4
alter table map
add (
constraint m_pk primary key ( category, product )
, constraint m_category_fk foreign key ( category ) references T4 ( value2 )
, constraint m_product_fk foreign key ( product ) references T3 ( value1 )
) ;
Find incorrect mappings
-- T2 rows containing incorrect (invalid) mappings
-- -> all rows MINUS the correct ones
select T2.id, T2.value1_id, T2.value2_id
from T2
minus (
select T2.id, T2.value1_id, T2.value2_id
from T2
join (
--
select T4.id categoryid, T3.id productid, M.category, M.product
from T4
join map M on T4.value2 = M.category
join T3 on T3.value1 = M.product
--
) C -- correct mappings
on
C.productid = T2.value1_id
and C.categoryid = T2.value2_id
) ;
-- result
ID VALUE1_ID VALUE2_ID
2 07 NULL
DBfiddle
I would highly recommend that you create a table to represent the one-to-many relationship between T4 and T3. This would represent a first step towards fixing your design, while providing a simple way to solve your current question.
Here is a CREATE TABLE ... AS SELECT order that initializes such a table with your sample data :
create table cat AS
SELECT 1 t3_id, 2 t4_id FROM DUAL
UNION ALL SELECT 4, 2 FROM DUAL
UNION ALL SELECT 5, 2 FROM DUAL
UNION ALL SELECT 8, 2 FROM DUAL
UNION ALL SELECT 9, 2 FROM DUAL
UNION ALL SELECT 2, 3 FROM DUAL
UNION ALL SELECT 3, 1 FROM DUAL
UNION ALL SELECT 10, 1 FROM DUAL
UNION ALL SELECT 6, 4 FROM DUAL
UNION ALL SELECT 7, NULL FROM DUAL
;
With this table in place, indentifiying records incorrectly mapped is as simple as :
SELECT t2.*
FROM t2
WHERE t2.Value2_ID IS NOT NULL AND NOT EXISTS (
SELECT 1 FROM cat WHERE cat.t3_id = t2.Value1_ID AND cat.t4_id = t2.Value2_ID
)
This DB Fiddle demo with your sample data yields :
T1_ID | VALUE1_ID | VALUE2_ID
----: | --------: | --------:
5 | 2 | 2
6 | 4 | 3
6 | 10 | 2
7 | 7 | 2
Hint to further improve your design : you have a one-to-many relationship between T4 (families of aliments) and T3 (aliments). The classic way to represent this is to add a column in the child table (T3) that references the parent table.
If you can't create a table with the mappings from fruit to categories and you know that the values are static then just include the mappings into your query using a nested sub-query or a sub-query factoring clause:
Oracle Setup:
create table T2 ( id, value1_id, value2_id ) as
select 1, '01', 2 from dual union all
select 1, '02', 3 from dual union all
select 1, '03', 1 from dual union all
select 2, '04', 2 from dual union all
select 2, '05', 2 from dual union all
select 2, '02', 3 from dual union all
select 2, '06', 4 from dual union all
select 2, '07', null from dual union all
select 3, '08', 2 from dual union all
select 3, '02', 3 from dual union all
select 4, '09', 2 from dual union all
select 4, '10', 1 from dual union all
select 5, '02', 2 from dual union all
select 5, '10', 1 from dual union all
select 6, '04', 3 from dual union all
select 6, '10', 2 from dual union all
select 7, '07', 2 from dual;
Query:
WITH mappings ( name, category ) AS (
SELECT '01', 2 FROM DUAL UNION ALL
SELECT '02', 3 FROM DUAL UNION ALL
SELECT '03', 1 FROM DUAL UNION ALL
SELECT '04', 2 FROM DUAL UNION ALL
SELECT '05', 2 FROM DUAL UNION ALL
SELECT '06', 4 FROM DUAL UNION ALL
SELECT '07', NULL FROM DUAL UNION ALL
SELECT '08', 2 FROM DUAL UNION ALL
SELECT '09', 2 FROM DUAL UNION ALL
SELECT '10', 1 FROM DUAL
)
SELECT *
FROM T2 t
WHERE NOT EXISTS (
SELECT 1
FROM mappings m
WHERE t.value1_id = m.name
AND ( t.value2_id = m.category
OR ( t.value2_id IS NULL AND m.category IS NULL ) )
);
Results:
ID | VALUE1_ID | VALUE2_ID
-: | :-------- | --------:
5 | 02 | 2
6 | 04 | 3
6 | 10 | 2
7 | 07 | 2
db<>fiddle here

How do I need to change my sql to get what I want in this case?

I have a table like following:
id value date
1 5 2015-01-10
2 5 2015-06-13
3 5 2015-09-05
4 11 2015-02-11
5 11 2015-01-10
6 11 2015-01-25
As can be seen, every value appears 3 times with different date. I want to write a query that returns the unique values that has the maximum date, which would be the following for the above table:
id value date
3 5 2015-09-05
4 11 2015-02-11
How could I do it?
This is the updated question:
The real question I am encountering is a little bit more complicated than the simplified version above. I thought I can move a step further once I know the answer to the simplified version, but I guest I was wrong. So, I am updating the question herein.
I have 2 tables like following:
Table 1
id id2 date
1 2 2015-01-10
2 5 2015-06-13
3 9 2015-09-05
4 10 2015-02-11
5 26 2015-01-10
6 65 2015-01-25
Table 2
id id2 data
1 2 A
2 5 A
3 9 A
4 10 B
5 26 B
6 65 B
Here, Table 1 and Table 2 are joined by id2
What I want to get is two records as follows:
id2 date data
9 2015-01-10 A
10 2015-02-11 B
You can use row_number to select the rows with the greatest date per value
select * from (
select t2.id2, t1.date, t2.data,
row_number() over (partition by t2.data order by t1.date desc) rn
from table1 t1
join table2 t2 on t1.id = t2.id2
) t where rn = 1
select a.id, a.value, a.date
from mytable a,
( select id, max(date) maxdate
from mytable b
group by id) b
where a.id = b.id
and a.date = b.maxdate;
Oracle Setup:
CREATE TABLE Table1 ( id, id2, "date" ) AS
SELECT 1, 2, DATE '2015-01-10' FROM DUAL UNION ALL
SELECT 2, 5, DATE '2015-06-13' FROM DUAL UNION ALL
SELECT 3, 9, DATE '2015-09-05' FROM DUAL UNION ALL
SELECT 4, 10, DATE '2015-02-11' FROM DUAL UNION ALL
SELECT 5, 26, DATE '2015-01-10' FROM DUAL UNION ALL
SELECT 6, 65, DATE '2015-01-25' FROM DUAL;
CREATE TABLE Table2 ( id, id2, data ) AS
SELECT 1, 2, 'A' FROM DUAL UNION ALL
SELECT 2, 5, 'A' FROM DUAL UNION ALL
SELECT 3, 9, 'A' FROM DUAL UNION ALL
SELECT 4, 10, 'B' FROM DUAL UNION ALL
SELECT 5, 26, 'B' FROM DUAL UNION ALL
SELECT 6, 65, 'B' FROM DUAL;
Query:
SELECT MAX( t1.id ) KEEP ( DENSE_RANK LAST ORDER BY t1."date" ) AS id,
MAX( t1.id2 ) KEEP ( DENSE_RANK LAST ORDER BY t1."date" ) AS id2,
MAX( t1."date" ) AS "date",
t2.data
FROM Table1 t1
INNER JOIN
Table2 t2
ON ( t1.id = t2.id AND t1.id2 = t2.id2 )
GROUP BY t2.data
Output:
ID ID2 date DATA
---------- ---------- ------------------- ----
3 9 2015-09-05 00:00:00 A
4 10 2015-02-11 00:00:00 B
Query 2:
SELECT id,
id2,
"date",
data
FROM (
SELECT t1.*,
t2.data,
ROW_NUMBER() OVER ( PARTITION BY t2.data ORDER BY t1."date" DESC ) AS rn
FROM Table1 t1
INNER JOIN
Table2 t2
ON ( t1.id = t2.id AND t1.id2 = t2.id2 )
)
WHERE rn = 1;
Output:
ID ID2 date DATA
---------- ---------- ------------------- ----
3 9 2015-09-05 00:00:00 A
4 10 2015-02-11 00:00:00 B