【发布时间】:2010-10-01 17:40:12
【问题描述】:
一般情况
当您想向关系的外部添加条件时,如何跨多对多关系执行左连接?
具体案例
我们正在处理两个表:team 和 pool。还有一个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));
理想的解决方案
理想的解决方案是:
- 不需要更改我的架构(ORM 真的希望这样)
- 需要一个非 UNION 查询。
尝试的解决方案
- 使用从
team到team_pool和team_pool到pool的INNER JOIN 而不是LEFT JOIN。问题:我们失去了不属于某个池的团队 - LEFT JOIN 从
team到team_pool和team_pool到pool,使用pool上的stage_id匹配我们正在寻找的条件。问题:当一个团队属于多个池时,我们会得到多个结果。添加 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
【问题讨论】:
-
如果 pool 为空,Team 2 如何拥有 stage_id?
-
如果一个团队属于多个池,您能否添加到您的理想化结果中以显示您的期望?