简体   繁体   中英

PL/SQL — Join Child Tables With Unrelated Rows

I'm trying to perform a join in PL/SQL to get a list of parent records with multiple child tables back as part of a single query. I'm not an Oracle expert. If I wrote a query like this:

SELECT PEOPLE.PersonName, JOBS.JobName, CREDENTIALS.CredentialName 
  FROM PEOPLE
  LEFT OUTER JOIN JOBS
    ON PEOPLE.PersonName = JOBS.PersonName
  LEFT OUTER JOIN CREDENTIALS
    ON PEOPLE.PersonName = CREDENTIALS.PersonName
  WHERE PEOPLE.PersonName = 'James'

I would get a table back that lists every combination of job and credential like so:

RN PERSON    JOB         CREDENTIAL
1  James     Developer   MBA
2  James     Developer   PhD
3  James     Developer   MCAD
4  James     QA          MBA
5  James     QA          PhD
6  James     QA          MCAD

That's fine, and exactly how you expect a left outer join to work. But what I need is for the JOB and CREDENTIAL columns to only list each element once and be unrelated to each other -- but still list James' child records on, and only on, rows where PERSON is James.

RN PERSON    JOB         CREDENTIAL
1  James     Developer   MBA
2  James     QA          PhD
3  James     (null)      MCAD

But I'm not sure how to write this join. (The idea is that C# code will take the query results and convert it into one parent PERSON object with lists of references to two child JOB objects and three child CREDENTIAL objects.

Outside this example, though, there's actually a lot more than two child tables, so I can't filter a result-set which is the product of all the child-combinations; I need the columns to be unrelated lists.

I'm willing to deal with hairy SQL to achieve this, but it needs to be one query and not multiple queries with the results combined on the C# side.

Thanks to anyone who can help!

You need to enumerate each list and then use that for joining:

select p.PersonName, j.JobName, c.CredentialName
from Person p left outer join
     (select j.*,
             row_number() over (partition by PersonName order by jobname) as seqnum
      from jobs
     ) j
     on p.PersonName = j.PersonName full outer join
     (select c.*,
             row_number() over (partition by PersonName order by CredentialName) as seqnum
      from Credentials
     ) c
     on p.PersonName = c.PersonName and
        j.seqnum = c.seqnum
WHERE p.PersonName = 'James'

This query is doing more work, because it assigns seqnum for all persons. You can put the WHERE clause in the subqueries to make it more efficient, if you are really only selecting one person at a time.

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