简体   繁体   中英

SQL query for many-to-many self-join

I have a database table that has a companion many-to-many self-join table alongside it. The primary table is part and the other table is alternate_part (basically, alternate parts are identical to their main part with different #s). Every record in the alternate_part table is also in the part table. To illustrate:

`part`

| part_id | part_number | description |
|---------|-------------|-------------|
|       1 |    00001    |    wheel    |
|       2 |    00002    |     tire    |
|       3 |    00003    |   window    |
|       4 |    00004    |     seat    |
|       5 |    00005    |    wheel    |
|       6 |    00006    |     tire    |
|       7 |    00007    |   window    |
|       8 |    00008    |     seat    |
|       9 |    00009    |    wheel    |
|      10 |    00010    |     tire    |
|      11 |    00011    |   window    |
|      12 |    00012    |     seat    |


`alternate_part`

| main_part_id | alt_part_id |
|--------------|-------------|
|            1 |           5 | // Wheel
|            5 |           1 | // |
|            5 |           9 | // |
|            9 |           5 | // |
|            2 |           6 | // Tire
|            6 |           2 | // |
|          ... |         ... | // |

I am trying to produce a simple SQL query that will give me a list of all alternates for a main part. The tricky part is: some alternates are only listed as alternates of alternates , it is not guaranteed that every viable alternate for a part is listed as a direct alternate. eg, if 'Part 3' is an alternate of 'Part 2' which is an alternate of 'Part 1', then Part 3 is an alternate of Part 1 (even if the alternate_part table doesn't list a direct link). The reverse is also true (Part 1 is an alternate of Part 3).

Basically, right now I'm pulling alternates and iterating through them

SELECT p.*, ap.*
FROM part p
INNER JOIN alternate_part ap ON p.part_id = ap.main_part_id

And then going back and doing the same again on those alternates. But, I think there's got to be a better way.

The SQL query I'm looking for will basically give me:

| part_id | alt_part_id |
|---------|-------------|
|       1 |           5 |
|       1 |           9 |

For part_id = 1, even when 1 & 9 are not explicitly linked in the alternates table.

Note: I have no control whatever over the structure of the DB, it is a distributed software solution. Note 2: It is an Oracle platform, if that affects syntax.

You have to create hierarchical tree , probably you have to use connect by prior , nocycle query something like this

select distinct p.part_id,p.part_number,p.description,c.main_part_id
from part p
left join (
            select main_part_id,connect_by_root(main_part_id) real_part_id
            from alternate_part
            connect by NOCYCLE prior main_part_id = alternate_part_id
        ) c 
on p.part_id = c.real_part_id and p.part_id != c.main_part_id
order by p.part_id

You can read full documentation about Hierarchical queries at http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries003.htm

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