Sql 使用条件跨多对多表执行左联接
一般情况 当您要向关系的外部添加条件时,如何跨多对多关系执行左联接 具体案例 我们正在处理两个表:Sql 使用条件跨多对多表执行左联接,sql,mysql,Sql,Mysql,一般情况 当您要向关系的外部添加条件时,如何跨多对多关系执行左联接 具体案例 我们正在处理两个表:team和pool。还有一个team\u pool表作为它们之间的多对多连接表。此外,pool还有一个stage\u id列 我想检索在特定阶段拥有该团队资源库的所有团队。如果池不存在,我希望池为NULL。理想化结果样本: +--------+----------+------+ | team | stage_id | pool | +--------+----------+------+ |
team
和pool
。还有一个team\u pool
表作为它们之间的多对多连接表。此外,pool
还有一个stage\u 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真的希望这样做)
- 需要单个非联合查询
- 使用内部联接,而不是从
到team
和team\u pool
到team\u pool
的左联接。问题:我们失去了不属于游泳池的球队pool
- 左键从
连接到team
和team\u pool
连接到team\u pool
,条件是pool
上的pool
与我们要查找的匹配。问题:当一个团队属于多个池时,我们会得到多个结果。通过添加组没有帮助stage\u id
stage\u id
添加到team\u池中,而不是使用联合或子查询。这样做的另一个好处是,我可以强制执行团队每个阶段只能属于一个池。它还使查询变得简单:
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
简而言之,不可能满足你所有的标准 更详细的回答:通过一个工会,你很有可能获得所有的结果。上半场将展示在该阶段有游泳池的球队;第二个将显示不需要的团队
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
如果我理解您模式背后的概念,那么我认为
stage\u id
应该是team\u pool
中的一列,而不是pool
。阶段不是池的属性,它是团队映射到池的一个因素,对吗
不管怎样,这就是我在Oracle中编写查询的方式。我不确定这种语法是否适合MySQL。您可能希望参数化stage\u 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
如果您只需要一个阶段,您可以将表连接在一起。如果找不到池,则池名称将为空。例如,对于
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
如果要查询所有阶段,可以使用交叉联接
为每个团队阶段组合生成一行。然后,左联接为每行搜索一个池:
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\u id
来自交叉连接,如果找不到池,它将不会是null
。不知道这是否可行,因为我现在没有可以使用的数据库,但我认为这应该可行。基本上创建两个左连接的“表”,然后再次左连接它们。如果它真的起作用,我无法想象它会有多好的表现
更新
简化了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
我们很清楚:
你想提供一个团队和一个舞台
您要返回:
所有团队在提供的阶段与您提供的团队共享任何池
在提供的阶段没有游泳池的所有球队
在所提供的阶段,与您提供的团队共享任何池的任何团队的所有池/团队组合
我很确定这可以在没有工会的情况下完成,但我不完全清楚你想要什么结果
首先,海事组织:
您的初始选择应该在团队表上
您应该在JOIN
子句而不是WHERE
子句中为池添加条件
一旦有了所需的阶段,您应该再次加入团队表,以介绍所有团队池如果池为空,团队2如何拥有阶段id?您能否将其添加到理想结果中,以显示如果一个团队属于多个池,您的期望值?阶段是池的一个属性(池存在于某个阶段)。如果在联合和将stage_id添加到team_池之间进行选择,我将选择后者。我避免将stage_id添加到team_pool的主要原因是,我使用的ORM使这样做有点烦人。SQL摘要:将pool和team_pool连接在一起,就像一个表,然后使用team_id将team连接到新的伪表。将pool连接到team_pool可能使用内部连接;这只是一种将team\u id链接到pool\u id的方法。一旦建立了这个方法,那么您应该能够将team.team\u id链接到任何p.team\u id,而不需要重复(我认为)。