我有两个带有给定字段的表
HighSchooler
喜欢
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;
答案 0 :(得分:3)
尝试使用规则(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)
答案 1 :(得分:1)
您的查询是正确的,但它正在使用表格的笛卡尔积,正如您所说的那样不是最优的。当您编写select * from a,b
时,a的所有行和b的所有行组合在一起以形成具有大小(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;
请参阅fiddle:
答案 2 :(得分:1)
关键的自连接是在对Likes表的两个引用之间。然后需要将其连接两次到HighSchoolers表以获取两个人的名字。
SELECT l1.id1, l1.id2
FROM Likes AS l1
JOIN Likes AS l2
ON l1.id1 = l2.id2 AND l1.id2 = l2.id1;
这给出了ID对的列表,其中每个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
现在用名字整理一下:
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
是'对'的助记符。