Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 New to SQL Server Programming
 One-To-Many Joining Query

Author  Topic 

adam2k1
Starting Member

6 Posts

Posted - 2009-03-16 : 07:30:12
Heya,

i have a (probably) straight forward question regarding a SQL query:

What i want is to take every record in a table (tblReferral), and join to the LATEST RECORD ONLY on another (tblNameHistory), also to the LATEST RECORD ONLY on a 3rd (tblAddressHistory). I've added the table structures below to illustrate my question:

tblReferral
ReferralID (PK) | PersonID (FK) | field1
1 | 1 | anything
2 | 1 | something
3 | 2 | nothing
...

tblNameHistory
PersonID (PK) | Forename | Surname | dtStart | dtEnd
1 | John | Smith | 01/01/01 | 02/02/02
1 | John | Jones | 02/02/02 | 03/03/03
2 | Paul | Black | 01/01/01 | NULL
...

tblAddressHistory
PersonID (PK) | AddrLine1 | AddrLine2 | dtStart | dtEnd
1 | 1 Main Street | Leeds | 01/01/01 | 02/02/02
1 | 1 Small Street | Leeds | 02/02/02 | NULL
2 | 3 Little Lane | Leeds | 01/01/01 | NULL
...

Below is the desired output
ReferralID | PersonID | Forename | Surname | AddrLine1 | AddrLine2 | field1
1 | 1| John | Jones | 1 Small Street | Leeds | anything
2 | 1| John | Jones | 1 Small Street | Leeds | something
3 | 2| Paul | Black | 1 Small Street | Leeds | nothing
...


And the query i have is:
SELECT tblReferral.ReferralID,
tblReferral.PersonID,
(SELECT TOP 1 Forename FROM tblNameHistory WHERE tblNameHistory.PersonID = tblReferral.PersonID) Forename,
(SELECT TOP 1 Surname FROM tblNameHistory WHERE tblNameHistory.PersonID = tblReferral.PersonID) Surname,
(SELECT TOP 1 AddrLine1 FROM tblAddressHistory WHERE tblAddressHistory.PersonID = tblReferral.PersonID) AddrLine1,
(SELECT TOP 1 AddrLine2 FROM tblAddressHistory WHERE tblAddressHistory.PersonID = tblReferral.PersonID) AddrLine2,
tblReferral.field1,
FROM tblReferral

This works, but I'm confident there is a better, more efficient query that i could use. Any suggestions would be appreciated.

Thanks,

Adam

sakets_2000
Master Smack Fu Yak Hacker

1472 Posts

Posted - 2009-03-16 : 08:09:06
Your query doesn't account for the latest start date. I don't think what you have is right.
Go to Top of Page

sakets_2000
Master Smack Fu Yak Hacker

1472 Posts

Posted - 2009-03-16 : 08:10:51
You can edit your query to this to account for startdate,

 SELECT tblReferral.ReferralID,
tblReferral.PersonID,
(SELECT TOP 1 Forename FROM tblNameHistory WHERE tblNameHistory.PersonID = tblReferral.PersonID order by startdt desc) Forename,
(SELECT TOP 1 Surname FROM tblNameHistory WHERE tblNameHistory.PersonID = tblReferral.PersonID order by startdt desc) Surname,
(SELECT TOP 1 AddrLine1 FROM tblAddressHistory WHERE tblAddressHistory.PersonID = tblReferral.PersonID order by startdt desc) AddrLine1,
(SELECT TOP 1 AddrLine2 FROM tblAddressHistory WHERE tblAddressHistory.PersonID = tblReferral.PersonID order by startdt desc) AddrLine2,
tblReferral.field1
FROM tblReferral
Go to Top of Page

sakets_2000
Master Smack Fu Yak Hacker

1472 Posts

Posted - 2009-03-16 : 08:12:11
Or you can re-write it to this for better performance,

SELECT	a.ReferralID,
a.PersonID,
b.Forename,
b.Surname,
c.AddrLine1,
c.AddrLine2,
a.field1
FROM
tblReferral a
join (select personid,max(dtStart) as MaxDt from tblNameHistory group by personid)b on a.personId=b.personId and b.MaxDt=a.dtStart
join (select personid,max(dtStart) as MaxDt from tblAddressHistory group by personid)c on a.personId=c.personId and c.MaxDt=a.dtStart
Go to Top of Page

adam2k1
Starting Member

6 Posts

Posted - 2009-03-16 : 08:18:06
Sorry, that was a error in posting. my original query did include the ordering.

My problem though isn't with this query (or even your amended one, thanks) - I know that works and it returns the data I want.

The issue I have is that I suspect it's not very efficient and there is a better query i could use. Can anyone confirm if this is correct, and if so provide an alternative?

Thanks

Go to Top of Page

adam2k1
Starting Member

6 Posts

Posted - 2009-03-16 : 08:20:46
Cheers,

Thats what I was looking for - a way to join on a one-to-many but only look at the latest record.

Adam

Go to Top of Page

matty
Posting Yak Master

161 Posts

Posted - 2009-03-16 : 08:22:56
SELECT r.ReferralID,r.PersonID,nh.Forename,nh.Surname,ah.AddrLine1,ah.AddrLine2,r.field1
FROM tblReferral r
JOIN
(
SELECT PersonID,Forename,Surname,ROW_NUMBER() OVER(PARTITION BY PersonID ORDER BY dtStart DESC) AS Rownum FROM tblNameHistory
) nh
ON nh.PersonID = r.PersonID AND nh.rownum = 1
JOIN
(
SELECT PersonID,AddrLine1,AddrLine2,ROW_NUMBER() OVER(PARTITION BY PersonID ORDER BY dtStart DESC) AS Rownum FROM tblAddressHistory
) ah
ON ah.PersonID = r.PersonID AND ah.rownum = 1
Go to Top of Page

sakets_2000
Master Smack Fu Yak Hacker

1472 Posts

Posted - 2009-03-16 : 08:23:00
Did you check the one posted @ 03/16/2009 : 08:12:11 ?
Go to Top of Page

adam2k1
Starting Member

6 Posts

Posted - 2009-03-16 : 09:18:49
Thanks guys.

i don't have a large dataset to test the queries against but I will have soon enough - cheers for the advice.

Saket - started posting my response before I refreshed the page, so missed your 3rd post.

Go to Top of Page
   

- Advertisement -