views:

102

answers:

2

I have a table "Families", like so

FamilyID    PersonID    Relationship
-----------------------------------------------
F001        P001        Son
F001        P002        Daughter
F001        P003        Father
F001        P004        Mother
F002        P005        Daughter
F002        P006        Mother
F003        P007        Son
F003        P008        Mother

and I need output like

FamilyID    PersonID    Father  Mother
-------------------------------------------------
F001        P001        P003    P004
F001        P002        P003    P004
F001        P003        
F001        P004        
F002        P005                P006
F002        P006        
F003        P007                P008
F003        P008        

In which the PersonID of the Father and Mother for a given PersonID are listed (if applicable) in separate columns. I know this must be a relatively trivial query to write (and therefore to find instructions for), but I can't seem to come up with the right search terms. Searching "SQL recursive queries" has gotten me closest, but I can't quite translate those methods to what I'm trying to do here.

I'm trying to learn, so multiple methods are welcome, as is vocabulary I should read up on. Thanks!

A: 

In SQL Server, the feature you use to solve recursive problems like these are Common Table Expressions.

sheepsimulator
..which SQL Server started supporting in 2005 - the OP states 2000.
OMG Ponies
@OMG Ponies - Fair enough. Still think it might be helpful to the OP, though, given that they are new to the concepts. CTE is something worth knowing about that can be helpful to problems like this, so I'm not going to delete my answer.
sheepsimulator
thank you for this note--this isn't obvious from the linked documentation.
Stew
oops, sorry that was in reply to OMG Ponies--hadn't refreshed the page since sheepsimulator's comment.OMG Ponies says "SQL Server started supporting in 2005"--are Common Table Expressions used by other database servers, or just SQL Server 2005 and on?@sheepsimulator: it's definitely useful to know CTE can be used for this and related problems in newer versions of SQL Server; another reader may find this information useful, so it makes sense to leave it.thanks to all for responding!
Stew
@Stew: Oracle has supported the WITH clause (CTE syntax), calling it "Subquery Factoring" since Oracle 9i. I'm told that DB2 support the WITH syntax, but that's all I'm aware of. MySQL and SQLite do **not** support WITH syntax. Postgres does as of v8.4. Additionally, CTE support isn't necessarily recursive - it wasn't supported in Oracle until 11g. But CTE (and recursive ones) are ANSI standard.
OMG Ponies
+1  A: 

You can self join the table twice with outer joins to get what you want:

SELECT
    T1.FamilyID AS FamilyID,
    T1.PersonID AS PersonID,
    T2.PersonID AS Father,
    T3.PersonID AS Mother
FROM Families T1
LEFT JOIN Families T2
    ON T1.FamilyID = T2.FamilyID
   AND T1.Relationship IN ('Son', 'Daughter')
   AND T2.Relationship = 'Father'
LEFT JOIN Families T3
    ON T1.FamilyID = T3.FamilyID
   AND T1.Relationship IN ('Son', 'Daughter')
   AND T3.Relationship = 'Mother'

Result:

FamilyID  PersonID  Father  Mother  
F001      P001      P003    P004    
F001      P002      P003    P004    
F001      P003      NULL    NULL    
F001      P004      NULL    NULL    
F002      P005      NULL    P006    
F002      P006      NULL    NULL    
F003      P007      NULL    P008    
F003      P008      NULL    NULL    
Mark Byers
This is probably a better way to do it than using CTE, as it's portable and potentially less confusing.
sheepsimulator
This is quite lucid and works great--thanks!
Stew