简体   繁体   中英

SQL, Matching Rows Across Multiple Tables

If I have two tables, A and B which have identical layout of:

  • Forename
  • Middlename
  • Surname
  • Date of Birth

Table A contains my data, table B contains data I wish to compare to table A.

I'd like to return all matches that are full matches (Forename, Middlename and Surname) as well as partial matches (First initial, surname, dob).

What would be the most efficient way of doing this and being able to distinguish between the two?

My initial thoughts are that I could do this with two passes however there must be a more efficient way as over a large number of records this could be quite inefficient.

You can do this:

select T1.*, T2.*,  'exact-match' as mode
from T1 inner join T2
on T1.fname = T2.fname
and T1.mname = T2.mname
and T1.lname = T2.lname
and t1.dob = T2.dob

UNION

select t1.*, t2.*, 'partial-match' as mode
from T1 inner join T2
on left(T1.fname,1) = LEFT(T2.fname,1)
and T1.lname = T2.lname
and T1.dob = T2.dob
where T1.fname <> T2.fname    

The last line is there because otherwise exact matches would also satisfy the partial match test. You can get rid of that where-clause if you like. The second part of the query ignores middle name, and treats "Tim Q Jones" and "Tom X Jones" as a partial-match if they're born on the same day. That's what you asked for, right?

If you really want to avoid two queries, you could do something like this:

SELECT A.*,
       CASE WHEN A.Middlename <> B.Middlename) THEN 'Partial' 
            ELSE 'Full' 
       END AS MatchType
FROM A
JOIN B ON (A.Forename = B.Forename AND
           A.Middlename = B.Middlename AND
           A.Surname = B.Surname)
          OR
          (LEFT(A.Forename,1) = LEFT(B.Forename,1) AND
           A.Surname = B.Surname AND
           A.DoB = B.DoB)  

A JOIN with two different sets of JOIN criteria, and a case in the select that identifies which of the sets must have resulted in the joined records (If Middlename doesn't match, it must not have been a "full" match that resulted in the join).

Select 
          T1.Forename
        , T1.Middlename
        , T1.Surname
        , T1.[Date of Birth]
        , Case When T1.[Forename] = T2.[Forename] and T1.Middlename = T2.Middlename
               Then 'Full'
               else 'Partial'
          end as Match_Type
    From Table1 as T1
    Inner Join Table2
    on Left(Table1.[Forename], 1) = Left(Table2.[Forename], 1)
        and Table1.[Date Of Birth] = Table2.[Date Of Birth] 
        and Table1.Surname = Table2.Surname

This will do it in a single pass. The condition for recognizing a full match has to be on both forename and middlename , otherwise it will classify some matches incorrectly.

select Forename, Middlename, Surname, DateOfBirth,
    Case
    when A.ForeName=B.ForeName and A.Middlename = B.middlename then 'full'
    Else 'partial'
    end as MatchType
from A
inner join B on
  -- (Forename, Middlename and Surname)
  (A.ForeName=B.ForeName
  and A.Middlename = B.middlename
  and A.Surname = B.surname)
or
  -- (First initial, surname, dob)
  (A.ForeName LIKE LEFT(B.ForeName,1)+'%'
  and A.Surname = B.surname
  and A.DateOfBirth = B.DateOfBirth)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM