Here are a few options for sample data you posted:
SQL> with
2 orders (id, order_num) as
3 (select 1, 101 from dual union all
4 select 2, 102 from dual union all
5 select 3, 103 from dual
6 ),
7 dates (order_id, log_date, user_name) as
8 (select 1, date '2022-05-27', 'Anthony' from dual union all
9 select 1, date '2022-04-16', 'Paul' from dual union all
10 select 1, date '2022-05-19', 'Daniel' from dual union all
11 select 2, date '2022-02-02', 'Chris' from dual union all
12 select 2, date '2022-03-18', 'Jenny' from dual union all
13 select 2, date '2022-02-12', 'Sonya' from dual union all
14 select 3, date '2022-06-06', 'Daniel' from dual union all
15 select 3, date '2022-06-07', 'Jacob' from dual
16 )
Oldfashioned way scans the dates
table twice (once to find the first log date in a subquery, and to join it with the orders table) so it isn't very efficient for large data sets.
17 select o.order_num, d.user_name
18 from orders o join dates d on d.order_id = o.id
19 where d.log_date = (select min(d1.log_date)
20 from dates d1
21 where d1.order_id = d.order_id
22 )
23 order by o.order_num;
ORDER_NUM USER_NAME
---------- ----------
101 Paul
102 Chris
103 Daniel
SQL>
Another option uses a CTE with the row_number
analytic function to "sort" rows by log date per each order ID, and then joins result of that CTE with orders table to get the final result, filtering only rows that ranked as the highest (use rank
function instead if there's a chance that two or more users log in on the same date):
17 temp as
18 (select d.order_id, d.user_name,
19 row_number() over (partition by d.order_id order by d.log_date) rn
20 from dates d
21 )
22 select o.order_num, t.user_name
23 from orders o join temp t on t.order_id = o.id
24 where t.rn = 1
25 order by o.order_num;
ORDER_NUM USER_NAME
---------- ----------
101 Paul
102 Chris
103 Daniel
SQL>
Or, you could use first_value
analytic function which is similar to previous option; as select
itself results in as many rows as there are in joined data set (join between orders and dates), use the distinct
keyword to remove duplicates:
17 select distinct o.order_num,
18 first_value(d.user_name) over (partition by order_id order by log_date) user_name
19 from orders o join dates d on d.order_id = o.id
20 order by o.order_num;
ORDER_NUM USER_NAME
---------- ----------
101 Paul
102 Chris
103 Daniel
SQL>