【问题标题】:Mysql Many to Many QueryMysql多对多查询
【发布时间】:2010-06-23 17:37:01
【问题描述】:

我的 mysql 数据库中有一个多对多的表设置。团队可以参加多场比赛,每场比赛有 2 支球队。在它们之间有一个名为 teams_games 的表。显示 CREATE TABLE 信息如下。

我一直在搞乱这个查询。在这一点上,我不在乎它是否需要子查询、连接或联合。我已经尝试了所有这些,但没有一个令人满意,我想我错过了一些东西。我一直存在的断开连接是从每场比赛中找到两个团队 id,然后使用 tid 来获取团队信息。

我想做的是,如果给定一个游戏 id (gid),我可以查询找到:

home_team_name, home_team_id, away_team_name, away_team_id, team_league(客队和主场是同一个联赛),所有比赛表信息

Table Create Table

 teams  CREATE TABLE `teams` (
 `tid` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(60) NOT NULL,
`league` varchar(2) NOT NULL,
`active` tinyint(1) NOT NULL,
PRIMARY KEY (`tid`)

)

CREATE TABLE teams_games (

`tid` int(10) unsigned NOT NULL,
`gid` int(10) unsigned NOT NULL,
`homeoraway` tinyint(1) NOT NULL,
PRIMARY KEY (`tid`,`gid`),
KEY `gid` (`gid`),
CONSTRAINT `teams_games_ibfk_1` FOREIGN KEY (`tid`) REFERENCES `teams` (`tid`),
CONSTRAINT `teams_games_ibfk_2` FOREIGN KEY (`gid`) REFERENCES `games` (`gid`)

)

CREATE TABLE games (

`gid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`location` varchar(60) NOT NULL,
`time` datetime NOT NULL,
`description` varchar(400) NOT NULL,
`error` smallint(2) NOT NULL,
`home_score` smallint(2) DEFAULT NULL,
`away_score` smallint(2) DEFAULT NULL,
PRIMARY KEY (`gid`)

)

【问题讨论】:

  • 尝试了不同的子查询和连接。从网上拼凑代码并猜测我的方式,但没有成功。我的问题已经很长了,所以我不想用更多的东西来填满它。

标签: sql mysql select


【解决方案1】:

为什么不直接删除teams_games 表并更改games

CREATE TABLE games (

 `gid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`location` varchar(60) NOT NULL,
`time` datetime NOT NULL,
`description` varchar(400) NOT NULL,
`error` smallint(2) NOT NULL,
`home_score` smallint(2) DEFAULT NULL,
`away_score` smallint(2) DEFAULT NULL,
`home_tid` int(10) unsigned NOT NULL,
`away_tid` int(10) unsigned NOT NULL,
PRIMARY KEY (`gid`)
)

然后你可以写一个简单的连接,比如:

SELECT 
    g.*, 
    h.name as home_team, 
    a.name as away_team, 
    h.league as league 
FROM games AS g 
    INNER JOIN teams AS h ON g.home_tid = h.tid
    INNER JOIN teams as a ON g.away_tid = a.tid
WHERE gid = ?

【讨论】:

  • 最简单的解决方案,因为一个游戏只能有,而且必须有 2 个团队参与。这不是多对多的情况,是多对二的情况,所以根本不需要中间连接表
  • 我这样做的原因是因为我想成为一个好的 sql 公民并掌握整个多对多事情的窍门。所以是的,我让它变得更加困难,它需要在这种情况下并且最初打算这样做但决定反对它。
【解决方案2】:

我假设 homeoraway = 1 表示 home,homeoraway = 0 表示离开。

SELECT g.*, ht.name, ht.tid, at.name, at.tid, ht.league
FROM games g
JOIN team_games htg ON htg.gid = g.gid AND htg.homeoraway = 1
JOIN team ht ON ht.tid = htg.tid
JOIN team_games atg ON atg.gid = g.gid AND atg.homeoraway = 0
JOIN team at ON at.tid = atg.tid

这可以通过将比赛加入到 team_games 为主队,然后加入球队以获取球队信息,然后为客队做同样的事情。

【讨论】:

  • 答案的原始版本中的那些。现在您已将它们更改为内部连接,我已恢复 -1。哦,关于你的“反对票”:你是我的英雄。
  • 这很好用,非常简洁易懂。您确实在 g.gid 的末尾省略了 WHERE 子句,但这很明显该怎么做。谢谢。
【解决方案3】:

我假设 1 = 在家,2 = 离开。你可以适当改变。

SELECT
    HT.name AS home_team_name,
    HT.tid AS home_team_id,
    AT.name AS away_team_name,
    AT.tid AS away_team_id,
    HT.league AS team_league
FROM
    teams_games HTG
INNER JOIN teams_games ATG ON
    ATG.gid = HTG.gid AND
    ATG.homeoraway = 2
INNER JOIN teams HT ON
    HT.tid = HTG.tid
INNER JOIN teams AT ON
    AT.tid = ATG.tid
WHERE
    HTG.gid = ???
    HTG.homeoraway = 1

【讨论】:

  • 工作得很好,谢谢汤姆。我选择马库斯的答案只是因为它更清晰、更简洁。
【解决方案4】:
select 
  th.name as home_team_name,
  th.tid as home_team_id,
  ta.name as away_team_name,
  ta.tid as away_team_id,
  th.league as team_league,
  g.* 
from games g
  inner join teams_games tgh on (g.gid = tgh.gid and tgh.homeoraway = <HOME_VALUE>)
  inner join teams_games tga on (g.gid = tga.gid and tga.homeoraway = <AWAY_VALUE>)
  inner join teams th on (tgh.tid = th.tid)
  inner join teams ta on (tga.tid = ta.tid)
where
  g.gid = <GAME_ID>

【讨论】:

    猜你喜欢
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2017-06-29
    相关资源
    最近更新 更多