I have the following location hierarchy. Jobs are assigned to locations. If I have just the location name how can I return all jobs in that location and in any place that comes under that location?
E.g if I select Leeds
or Oakwood
then only jobs 1 and 2 should be returned. If I select Yorkshire
or England
or Uk
or Europe
then all 3 jobs would be returned.
Locations:
id | name | continent | country | admin1 | admin2 | city
-------------------------------------------------------------------------------------
1 | Europe | | | | |
2 | UK | Europe | | | |
3 | England | Europe | UK | | |
4 | Yorkshire | Europe | UK | England | |
5 | Leeds | Europe | UK | England | Yorkshire |
6 | Oakwood | Europe | UK | England | Yorkshire | Leeds
Jobs:
id | location_id
--------------------
1 | 6
2 | 6
3 | 4
This is straight forward when you know which column to filter by e.g
Select jobs.*
from jobs
INNER JOIN locations on locations.id = jobs.location_id
where locations.name = 'Europe' OR location.continent = 'Europe'
Select jobs.*
from jobs
INNER JOIN locations on locations.id = jobs.location_id
where locations.name = 'UK' OR location.country = 'UK'
But how can you achieve the same when you don't know which column to filter in.
答案 0 :(得分:0)
您使用的数据库模型存在两个主要问题:
尽管如此,尽管使用了难看的SQL查询,仍然可以检索到您拥有的信息。在这里:
select
j.*
from (
select -- select the initial location
from locations l
where name = 'Yorkshire'
union
select -- select all children locations
from locations l
join locations r
on (l.continent is null and l.name = r.continent)
or (l.continent is not null and l.country is null and l.name = r.country)
or (l.continent is not null and l.country is not null and l.admin1 is null and l.name = r.admin1)
or (l.continent is not null and l.country is not null and l.admin1 is not null and l.admin2 is null and l.name = r.admin2)
or (l.continent is not null and l.country is not null and l.admin1 is not null and l.admin2 is not null and l.city is null and l.name = r.city)
where l.name = 'Yorkshire'
) x
join jobs j on j.location_id = x.id
注意:此查询不使用CTE(公用表表达式),因此适用于MySQL 5.x和MySQL 8.x。
答案 1 :(得分:0)
您可以使用case when
表达式:
select jobs.*
from (
select id
from locations
where name = "Europe"
union all
select child.id
from locations main
inner join locations child
on main.name = case when main.continent is null then child.continent
when main.country is null then child.country
when main.admin1 is null then child.admin1
when main.admin2 is null then child.admin2
else child.city
end
where main.name = "Europe"
) sub
inner join jobs
on jobs.location_id = sub.id
答案 2 :(得分:0)
不更改表格? 在所有定义关系的字段上将位置本身结合起来。
示例:
select loc.name, job.*
from Locations as loc
join Locations as parent_loc
on parent_loc.name in (loc.name, loc.continent, loc.country, loc.admin1, loc.admin2, loc.city)
join Jobs as job on job.location_id = loc.id
where parent_loc.name = 'UK'
但是此模型并未真正归一化。重复的名称太多。
使用外键指向表的pk可能是值得的。
然后,更改名称将不是一个小问题。
例如在此test
中或者您可以切换到嵌套集模型。
不需要像邻接表模型那样进行递归。
有关这两个模型here