1

我有两个带有给定字段的表

  1. 高中生

    • 姓名
    • 年级
    • ID
  2. 喜欢

    • id1
    • id2

HighSchooler 保存有关高中生的信息,而 Likes 是一个关系表,显示谁在高中时喜欢谁。id1 的学生喜欢 id2 的学生。有两种方式的关系(当约翰喜欢露西但露西不喜欢约翰时)和两种方式的关系(当阿尔伯特喜欢桑德拉而桑德拉也喜欢阿尔伯特时)。

我需要一个返回两列的查询,其中两列的名称是双向关系,即如果 A 喜欢 B 并且 B 喜欢 A,那么示例结果集将是

name | name
A       B

我摆弄它并提出了这个查询,但我不理解它,也不认为它是最佳的。

SELECT DISTINCT a.name, b.name 
FROM Highschooler a, Highschooler b, Likes l1 
JOIN Likes l2 on l1.ID1=l2.ID2 
WHERE a.ID=l1.ID2 AND b.ID=l1.ID1 AND a.ID=l2.ID1 AND a.ID > b.ID;
4

3 回答 3

3

尝试使用规则将 Likes 表与自身连接起来(l1.id1 = l2.id2) and (l1.id2 = l2.id1)

例子:

SELECT
   a.name AS a_name,
   b.name AS b_name
FROM
   HighSchooler AS a
   INNER JOIN Likes AS l1
      ON (a.id = l1.id1)
   INNER JOIN Likes AS l2
      ON ((l1.id1 = l2.id2) AND (l1.id2 = l2.id1) AND (l1.id1 > l2.id1))
   INNER JOIN HighSchooler AS b
      ON (l2.id1 = b.id)

http://sqlfiddle.com/#!2/44a07/6

于 2013-03-09T21:46:46.980 回答
1

您的查询是正确的,但它使用的是表的笛卡尔积,正如您所说,这不是最佳的。当您编写select * from a,ba 的所有行和 b 的所有行组合在一起以形成一个具有 size(a)*size(b) 行的新表时。您正在使用三个表来执行此操作,因此您正在创建一个巨大的表,然后从中选择您想要的几行。内连接可以更有效地做到这一点。

SELECT
a.name AS name_a, b.name AS name_b
FROM
HighSchooler AS a
INNER JOIN Likes AS l1
ON a.id = l1.id1
INNER JOIN Likes AS l2
ON l1.id1 = l2.id2 AND l1.id2 = l2.id1 AND l1.id1 < l1.id2
INNER JOIN HighSchooler AS b
ON l1.id2 = b.id;

请看小提琴

于 2013-03-09T22:26:18.807 回答
1

关键自联接位于对 Likes 表的两个引用之间。然后需要将其连接到 HighSchoolers 表两次以获取两个人的姓名。

步骤 1 彼此喜欢的 ID 对

SELECT l1.id1, l1.id2
  FROM Likes AS l1
  JOIN Likes AS l2
    ON l1.id1 = l2.id2 AND l1.id2 = l2.id1;

这给出了彼此喜欢的 ID 对列表。

步骤 2 彼此喜欢且不重复的 ID 对

唯一的障碍是它给了每对两次。因此,诀窍是要注意在两行之一中,id1值小于id2值。作为一个可能有益的副作用,这消除了任何喜欢自己的人。

SELECT l1.id1, l1.id2
  FROM Likes AS l1
  JOIN Likes AS l2
    ON l1.id1 = l2.id2 AND l1.id2 = l2.id1;
 WHERE l1.id1 < l1.id2

步骤 3 彼此喜欢的名字对

现在用名字整理一下:

SELECT h1.name AS name1, h2.name AS name2
  FROM (SELECT l1.id1, l1.id2
          FROM Likes AS l1
          JOIN Likes AS l2
            ON l1.id1 = l2.id2 AND l1.id2 = l2.id1
         WHERE l1.id1 < l1.id2
       ) AS p
  JOIN HighSchoolers AS h1 ON p.id1 = h1.id
  JOIN HighSchoolers AS h2 ON p.id2 = h2.id

p是“对”的助记符。

于 2013-03-09T22:39:48.037 回答