Reputation: 69
I want to join tables in such a way that it fetches only latest record from one of the tables:
The following are my data
Table_One:
+----+------+
| ID | Name |
+----+------+
| 1 | John |
| 2 | Tom |
| 3 | Anna |
+----+------+
Table_two:
+----+----------+-----------+
| ID | Visit ID | Date |
+----+----------+-----------+
| 1 | 2513 | 5/5/2001 |
| 1 | 84654 | 10/5/2012 |
| 1 | 454 | 4/20/2018 |
| 2 | 754 | 4/5/1999 |
| 2 | 654 | 8/8/2010 |
| 2 | 624 | 4/9/1982 |
| 3 | 7546 | 7/3/1997 |
| 3 | 246574 | 6/4/2015 |
| 3 | 15487 | 3/4/2017 |
+----+----------+-----------+
Results needed after Join:
+----+------+----------+-----------+
| ID | Name | Visit ID | Date |
+----+------+----------+-----------+
| 1 | John | 454 | 4/20/2018 |
| 2 | Tom | 654 | 8/8/2010 |
| 3 | Anna | 246574 | 6/4/2015 |
+----+------+----------+-----------+
Upvotes: 4
Views: 11787
Reputation: 51008
Different database engines have varying ways to get the top row from table 2 per group (you can google for "SQL windowing functions" and your product). Since you don't state what engine you're using it's impossible to give the most appropriate or most performant solution.
The following method should work in most or all SQL engines but will not be especially performant over a large data set (it will benefit from a composite index Table2(ID, Date)). The details of how you specify the aliases for the tables may differ a bit among engines but you can use this as a guide. A windowing function solution will probably be more efficient.
SELECT ID, Name, VisitID, Date
FROM Table1 AS T1
INNER JOIN Table2 AS T2 ON T1.ID = T2.ID
WHERE NOT EXISTS (
SELECT * FROM Table2 AS T2B WHERE T2B.ID = T1.ID AND T2B.Date > T2.Date)
Upvotes: 2
Reputation: 12973
This is a working version of Hasan's answer:
SELECT ID, Name, [Visit ID], Date
FROM (
SELECT
t1.*, t2.[Visit ID], t2.Date,
ROW_NUMBER() OVER(PARTITION BY t1.ID ORDER BY Date DESC) AS rn
FROM Table_One t1
JOIN Table_Two t2 ON t1.ID = t2.ID
) AS t
WHERE rn = 1;
The output is:
ID | Name | Visit ID | Date |
---|---|---|---|
1 | John | 454 | 2018-04-20 |
2 | Tom | 654 | 2010-08-08 |
3 | Anna | 15487 | 2017-03-04 |
Note: The row returned for Anna is different to the one in the question, as the desired output is incorrect!
And here's a db<>fiddle
Upvotes: 0
Reputation: 1
This is the answer to your question
SELECT t1.ID, t1.Name, t2.visit_id, t2.Date
FROM table1 t1
INNER JOIN table2 t2 ON t1.ID = t2.ID
WHERE NOT EXISTS (
SELECT * FROM table2 t2b WHERE t2b.ID = t1.ID AND t2b.Date > t2.Date
)
Upvotes: 0
Reputation: 18408
You can filter out "latest visit" using
SELECT ID,MAX(DATE) FROM TABLE_TWO GROUP BY ID;
You then join that to TABLE_ONE (... ON .ID = <alias_of_your_aggregation>.ID) to pick up the Name column and then join that again to TABLE_TWO (... ON ID=ID AND DATE=DATE) if you need to pick up the VISIT_ID as well.
Specific DBMS's might have proprietary/idiosyncratic extensions typically serving the purpose of allowing the optimizer do a better job (e.g. allowing the optimizer to understand that the "joining back to TABLE_TWO can be eliminated). Thinking here of SELECT TOP 1 ... and the like.
Upvotes: 0
Reputation: 326
I'm not a 100% sure if this is correct since the Visit ID might just throw every record right back at you. However you can find some great documentation here: https://www.w3resource.com/sql/aggregate-functions/max-date.php
select t1.ID,t1.Name,t2.visit_ID, Max(t2.Date) from Table_Two t2
inner join Table_One t1
on(t2.ID=t1.ID)
group by t1.ID,t1.Name,t2.visit_ID
something like this should work though, i think that this is also the same as @Erwin Smout proposes
select a.ID, t1.Name, a.date,t2.Visit_ID (
select ID, max(date)'date' from Table_Two
group by ID) a
inner join Table_One t1
on( a.ID=t1.ID)
inner join Table_Two t2
on(a.ID=t2.ID and a.Date=t2.Date)
Upvotes: 0
Reputation: 633
SELECT ID,Name,Visit_ID,Date
FROM
(SELECT *, ROW_NUMBER() OVER(PARTITION BY ID Date DESC) as seq
FROM Table2 LEFT OUTER JOIN
Table1 ON Table2.ID = Table1.ID) as mainTable
WHERE seq = 1
Upvotes: 1
Reputation: 50173
I suspect you have SQL Server if so, then you can use APPLY
:
select o.*, tt.*
from Table_One o
cross apply ( select top 1 t.VisitDate, t.Date
from table_two t
where t.id = o.id
order by t.date desc
) tt;
Upvotes: 2