简体   繁体   中英

Joining a variable number of tables based on column value

I have a few Models in my code which is modeled in my MySQL database in this structure:

 Properties
+----+------+---------+
| id | name | address |
|----+------+---------|
| 1  | p1   | 123 st  |
| 2  | p2   | 123 st  |
| 2  | p3   | 123 st  |
+----+------+---------+

 Tenants (belongs to property)
+----+-------------+-------+
| id | property_id | suite |
|----+-------------+-------|
| 1  | 1           | s1    |
| 2  | 1           | s2    |
| 3  | 2           | s3    |
+----+-------------+-------+

 Costs (can belong to property or tenants)
+----+--------------+-----------+--------------+
| id | parent_model | parent_id | name         |
|----+--------------+-----------+--------------+
| 1  | property     | 1         | gardening    |
| 2  | property     | 2         | construction |
| 3  | tenant       | 1         | renovation   |
+----+--------------+-----------+--------------+

 Files (can belong to any model)
+----+--------------+-----------+--------------+
| id | parent_model | parent_id | name         |
|----+--------------+-----------+--------------+
| 1  | property     | 1         | file1.jpg    |
| 2  | tenant       | 2         | file2.pdf    |
| 3  | costs        | 3         | file3.doc    |
+----+--------------+-----------+--------------+

As you can see from the table structure all models can be linked back to a property record (either directly or via one or more intermediary tables).

In my code I want to write one query that will get the property.id of a file After looking over this question: Joining different tables based on column value I realized finding a "link" from a file to a property can be done via a few joins.

The number of joins needed is different based on whatever the parent_model is. For file.id = 1 its a matter of joining in the properties table. For file.id = 3 we must join in costs , tenants , and properties

How should a query be written that can get a property.id for all of my files records?


Edit: This would be a sample output:

+---------+-------------+
| file_id | property_id |
|---------+-------------|
| 1       | 1           |
| 2       | 1           |
| 3       | 1           |
+---------+-------------+

In this case all the files worked out to be associated with property_id 1 but this may not always be the case.

I don't think there's a shortcut. You need to traverse all the paths something along these lines

select -- property files
FileID, parent_id 
from Files 
where parent_model='property'
union
select -- property costs
FileID, c.parent_id
from
Files inner join costs C on Files.parent_id=c.id and c.parent_model='property'
where Files.parent_model='costs'
union
select -- tenant costs
FileID, t.parent_id
Files inner join costs C on Files.parent_id=c.id and c.parent_model='tenant'
inner join tenant t on t.id=c.parent_id  
where Files.parent_model='costs'
.... etc.

ie just string together all the variations then UNION

You should be able to do this like so:

SELECT
    P.id,
    P.name,
    P.address,
    F.name,
    ...
FROM
    Files F
LEFT OUTER JOIN Costs C ON
    F.parent_model = 'Cost' AND C.id = F.parent_id
LEFT OUTER JOIN Tenants T ON
    (F.parent_model = 'Tenant' AND T.id = F.parent_id) OR
    (C.parent_model = 'Tenant' AND T.id = C.parent_id)
LEFT OUTER JOIN Properties P ON
    (F.parent_model = 'Property' AND P.id = F.parent_id) OR
    (C.parent_model = 'Property' AND P.id = C.parent_id) OR
    (P.id = T.property_id)

Depending on your data, this might break down. I don't think that I like the table design in this case.

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