【问题标题】:SQL - Left join 2 foreign keys to 1 primary keySQL - 将 2 个外键左连接到 1 个主键
【发布时间】:2009-08-30 21:35:55
【问题描述】:

我有两张桌子,Games 和 Teams。我的 sql 语句应该是什么样子来制作一个包含链接到 TeamID1 和 TeamID2 字段的 TeamName 的游戏列表?我相信我可以使用左连接,但我不确定如何处理链接到一个主键的两个外键。非常感谢您提供的任何帮助。

游戏

游戏ID
TeamID1
TeamID2
结果

团队

团队ID
团队名称

【问题讨论】:

  • 不要使用左(外)连接;您希望两个团队都为人所知,并且信息会出现在团队表中。使用 (INNER) JOIN。

标签: sql mysql


【解决方案1】:

我经常看到人们对将一个表连接到自身或在同一个查询中多次连接(就像这里一样)的想法而苦苦挣扎。一旦掌握,它是一种很好的技术,可以用于行之间有很多关系的表格(例如必须互相比赛的团队列表!)。正如其他人指出的那样,您需要使用两个inner joins 来完成此操作:

select
    *
from
    games g
    inner join teams t1 on
        g.teamid1 = t1.teamid
    inner join teams t2 on
        g.teamid2 = t2.teamid

所以,如果您的 games 表如下所示:

GameID    TeamID1    TeamID2
----------------------------
     1          1          3
     2          4          2
     3          2          1

你会得到以下结果集:

g.GameID    g.TeamID1    g.TeamID2    t1.TeamID    t1.Name    t2.TeamID    t2.Name
----------------------------------------------------------------------------------
       1            1            3            1    Lions              3    Bears
       2            4            2            4    Oh My              2    Tigers
       3            2            1            2    Tigers             1    Lions

当然,如果我是我,为了可用性,我会在 select 语句中为这些列加上别名:

select
    g.GameID,
    t1.Name as Team1,
    t2.Name as Team2
from
    ...

这样,可以适当地命名列,而不是让t1t2 列共享相同的名称。

现在,解决关于 left join 是什么的困惑。您会看到,left join 将从第一个(或左)表中获取所有行,然后将连接条件中的任何行与第二个(或右)表匹配。对于左表中的任何行,您将在 right 表的所有列中获得 null

深入研究一个示例,假设有人出于某种原因在其中一行中为TeamID2 输入了null。我们也假设一个由TeamID 4 组成的团队曾经存在,但现在已经不存在了。

GameID    TeamID1    TeamID2
----------------------------
     1          1          3
     2          4          2
     3          1       null

现在,让我们看一下left join 在查询中的含义:

select
    *
from
    games g
    left join teams t1 on
        g.teamid1 = t1.teamid
    left join teams t2 on
        g.teamid2 = t2.teamid

从逻辑上讲,这将获取我们所有的games,然后将它们与各自的teams 匹配。但是,如果TeamID 不存在,我们将得到nulls。它看起来像这样:

g.GameID    g.TeamID1    g.TeamID2    t1.TeamID    t1.Name    t2.TeamID    t2.Name
----------------------------------------------------------------------------------
       1            1            3            1    Lions              3    Bears
       2            4            2         null    null               2    Tigers
       3            1         null            1    Lions           null    null

因此,left join在团队是可选的情况下是必需的。

在您的情况下,您将使用inner join 多次加入一个表。这是一种非常常见的做法,而且非常有用。它避免了子查询的一些陷阱(尤其是在 MySQL 上),同时允许您从表中获取数据以进行表内比较。这在尝试查找某事物或相关行的顺序时非常有用。

无论如何,我希望这个非常漫无边际的答案可以帮助某个地方的人。

【讨论】:

  • 有义务。我试试 :) 希望它对某人有所帮助,嗯?
  • 它没有将表连接到自身;它两次将游戏桌加入团队桌 - 这是不同的(即使团队被提及两次)。
  • @Jonathan:非常正确。将语义更改为更准确。
  • 感谢大家的帮助。这正是我试图弄清楚的,现在它很有意义!
【解决方案2】:
SELECT *
FROM Games G
INNER JOIN Teams T1
   ON G.TeamID1 = T1.TeamID
INNER JOIN Teams T2
   ON G.TeamID2 = T2.TeamID

【讨论】:

  • 我知道有人会更快:(
【解决方案3】:

我认为您不需要左外连接,除非游戏中的两支球队之一是可选的。在我看来,从逻辑上讲,两者似乎都是必需的,因此您的查询将如下所示:

SELECT *
FROM Games AS G
INNER JOIN Teams AS T1 ON T1.TeamID = G.TeamID1
INNER JOIN Teams AS T2 ON T2.TeamID = G.TeamID2

【讨论】:

    【解决方案4】:

    如果 TeamID1 和 TeamID2 不为 NULL,那么您要使用 INNER JOIN,否则您可以使用 LEFT JOIN。

    【讨论】:

      【解决方案5】:

      你需要使用别名:

      SELECT GameID, team1.TeamName, team2.TeamName
      FROM Games INNER JOIN teams team1 ON (Games.TeamID1 = team1.TeamID)
                 INNER JOIN teams team2 ON (Games.TeamID2 = team2.TeamID)
      

      【讨论】:

        猜你喜欢
        • 2011-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多