2010-10-01 53 views
2

一般情况执行左跨多到多表连接的条件

你如何执行左键跨越许多一对多的关系,加入时要一个条件添加到国外关系的一面?

具体案例

我们正在处理两个表:teampool。还有一个team_pool表作为它们之间的多对多联结表。此外,pool有一个stage_id列。

我想检索具有特定舞台的该团队的所有团队。如果池不存在,我希望池为NULL。示例,理想化结果:

+--------+----------+------+ 
| team | stage_id | pool | 
+--------+----------+------+ 
| Team 1 |  2 | C | 
| Team 2 |  NULL | NULL | //this team doesn't belong to a pool for this stage (but it could belong to a pool for a different stage) 
| Team 3 |  2 | G | 
| Team 3 |  2 | H | //if a team belongs to a 2 pools for the same stage 
| Team 4 |  2 | D | 

如果相关,我使用的是MySQL。

SQL

下面是用于创建表(简化)SQL:

CREATE TABLE team (id BIGINT AUTO_INCREMENT, name VARCHAR(50), PRIMARY KEY(id)); 
CREATE TABLE team_pool (team_id BIGINT, pool_id BIGINT, PRIMARY KEY(team_id, pool_id)); 
CREATE TABLE pool (id BIGINT AUTO_INCREMENT, stage_id BIGINT, name VARCHAR(40) NOT NULL, PRIMARY KEY(id)); 

理想的解决方案

理想的解决办法:

  • 不需要ch愤怒到我的模式(ORM真的想这样)
  • 需要一个单一的非UNION查询。

尝试的解决方案

  • 使用INNER JOIN,而不是一个LEFT JOIN从teamteam_poolteam_poolpool。问题:我们失去了球队不属于池
  • 从左边teamteam_poolteam_poolpool JOIN使用WITH条件是stage_idpool比赛是我们要寻找的。问题:当一个团队属于多个池时,我们会得到多个结果。添加一个GROUP BY没有帮助。

编辑:选择的解决方案

有很多很好的解决方案在这里。

鉴于我的理想解决方案是不可能的,我宁愿添加stage_id到team_pool比使用UNION或子查询。这还有一个好处,就是让我强制一个团队每个阶段只能属于一个团队。它也使查询变得简单:

SELECT t.name, p.name, tp.stage_id FROM team t LEFT JOIN team_pool tp ON t.id = tp.team_id AND tp.stage_id = 2 LEFT JOIN pool p ON p.id = tp.pool_id 
+0

如果队伍为空,队2如何获得stage_id? – Snekse 2010-10-01 17:47:21

+0

它不应该,我修好了。 – 2010-10-01 17:48:39

+0

如果团队属于多个泳池,您是否可以添加您的理想结果以显示您的期望? – Snekse 2010-10-01 17:51:34

回答

1

如果我理解你的架构背后的概念,那么我会认为stage_id应该是team_pool而非pool列。这个阶段不是游泳池的一个属性,它是团队到游泳池的映射的一个因素,对吧?

无论如何,这是我将如何在Oracle中编写查询。我不确定这个确切的语法是否适合MySQL。大概你会想参数化stage_id的文字值。

SELECT t.name, p.name 
    FROM (SELECT team.name, pool_id 
      FROM team LEFT JOIN team_pool 
      ON team_pool.team_id = team.team_id) t 
     LEFT JOIN (SELECT pool_id, name FROM pool WHERE stage_id = 2) p 
      ON p.pool_id = t.pool_id 
+0

舞台是游泳池的一个属性(游泳池在某个阶段存在)。如果选择在UNION和将stage_id添加到team_pool之间,我会选择后者。我避免将stage_id添加到team_pool的主要原因是因为我使用的ORM使得它有点烦人。 – 2010-10-01 18:02:09

1

简而言之,不可能满足您的所有条件。

较长的答案:很可能通过UNION获得所有结果。上半场将展示那些确实拥有这个阶段的球队;第二将显示没有的球队。

select ... 
from team 
left join team_pool 
    on team.id = team_pool.team_id 
left-join pool 
    on pool.id = team_pool.pool_id 
     and pool.stage_id = @stage 
UNION 
select distinct team.id, @stage, NULL 
from team 
where not exists 
    (select pool_id 
     from pool 
     inner join team_pool 
     on team_pool.pool_id = pool.pool_id 
     where team_pool.team_id = team.id 
     and pool.stage_id = @stage 
1

如果您只想寻找一个阶段,您可以将这些表格连在一起。如果没有找到池,池名称将为空。例如,对于stage = 2

select t.name, 2, pool.name 
from team t 
left join 
     (
     select team_id, p.name 
     from team_pool tp 
     join pool p 
     on  tp.pool_id = p.id 
     where p.stage_id = 2 
     ) pool 
on  pool.team_id = t.id 

如果您想查询所有的阶段,你可以使用一个cross join生成每个团队级组合一行。左加入,然后搜索的每一行池:

select t.name, s.stage_id, p.name 
from team t 
cross join 
     (
     select distinct stage_id 
     from pool 
     ) s 
left join 
     (
     select tp.team_id, p.stage_id, p.name 
     from team_pool tp 
     join pool p 
     on  tp.pool_id = p.id 
     ) pool 
on  pool.team_id = t.id 
     and pool.stage_id = s.stage_id 

因为stage_id来自交叉连接,如果没有池被发现也不会null

0

不知道这是否可行,因为我没有数据库我现在可以玩,但我认为这应该工作。基本上创建两个左连接的“表”,然后再将它们连接起来。如果它确实有效,我无法想象它会非常高效。

UPDATE 简化的SQL

SELECT t.name, p.stage_id, p.pool_name 
FROM team t 
LEFT JOIN 
    (SELECT pool.name as pool_name, pool.stage_id, team_pool.team_id as junc_team_id 
    FROM pool LEFT JOIN team_pool 
    ON team_pool.pool_id = pool.pool_id) p 
ON p.junc_team_id = t.team_id 
+0

SQL摘要:将池和team_pool联合起来,就像一个表一样,然后使用team_id将联接组留在新的伪表中。加入池到team_pool可能可能使用INNER JOIN;这只是一种获取链接到pool_id的team_id的方法。一旦建立,那么你应该能够将team.team_id链接到任何没有重复的p.team_id(我认为)。 – Snekse 2010-10-01 18:55:06

0

只是让我们很清楚:

你要提供一个团队,一个阶段

要返回: 所有球队在提供的阶段与您提供的球队共享任何球队 所有球队中没有任何球队提供阶段 任何球队/球队组合与所提供的球队在提供的阶段共享任何球场?

我敢肯定这可以在不UNION来完成,但我不是什么导致你后

担任首发是完全清楚,IMO:

你最初的选择应该是对球队表

您应该JOIN子句中添加标准池,而不是WHERE条款

你应该对球队表再次加入,一旦你有希望的阶段,以引入所有的球队池