[英]How to write this complex self join
I have two tables with given fields 我有给定字段的两个表
HighSchooler 高中生
Likes 喜欢
HighSchooler holds info on a high school student and Likes is a relationship table showing who likes who in the high school. HighSchooler拥有高中生的信息,而Likes是一个关系表,显示谁喜欢高中生。 Student with id1 likes student with id2. ID1的学生喜欢ID2的学生。 There are both one way relationships (when John likes Lucy but Lucy doesn't like John) and two way relationships (when Albert likes Sandra and Sandra also likes Albert). 两种关系都有(当约翰喜欢露西但露西不喜欢约翰时)和两种关系(当阿尔伯特喜欢桑德拉和桑德拉也喜欢阿尔伯特时)。
I need a query that returns two columns with the names of those in a two way relationship, ie if A likes B and B likes A, then a sample result-set would be 我需要一个查询,该查询返回两列,两列的名称具有双向关系,即如果A喜欢B,而B喜欢A,则样本结果集为
name | name
A B
I fiddle with it and came up with this query, but i don't understand it and don't think it is optimal. 我摆弄它,并提出了此查询,但我不明白,也不认为它是最佳的。
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;
Try joining Likes table with itself using the rule (l1.id1 = l2.id2) and (l1.id2 = l2.id1)
尝试使用规则(l1.id1 = l2.id2) and (l1.id2 = l2.id1)
Likes表与其自身连接
Example: 例:
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 http://sqlfiddle.com/#!2/44a07/6
Your query is correct but it is using Cartesian product of tables which as you said is not optimal. 您的查询是正确的,但使用的是表的笛卡尔积,正如您所说的不是最佳选择。 When you write select * from a,b
all the rows of a and all the rows of b are combined together to form a new table which has size(a)*size(b) rows. 当您select * from a,b
写入select * from a,b
所有行和select * from a,b
所有行将合并在一起以形成一个新表,该表具有size(a)* size(b)行。 You are doing that with three tables so you are creating a huge table and then select from it a few rows that you want. 您正在使用三个表来执行此操作,因此您要创建一个巨大的表,然后从表中选择所需的几行。 Inner join can do this more efficiently. 内部联接可以更有效地做到这一点。
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;
The key self-join is between two references to the Likes table. 关键自连接位于对Likes表的两个引用之间。 This then needs to be joined twice to the HighSchoolers table to get the names of the two people. 然后,需要将其两次连接到HighSchoolers表中,以获取两个人的名字。
SELECT l1.id1, l1.id2
FROM Likes AS l1
JOIN Likes AS l2
ON l1.id1 = l2.id2 AND l1.id2 = l2.id1;
This gives the list of pairs of IDs where each likes the other. 这给出了彼此相似的ID对的列表。
The only snag is that it gives each pair twice. 唯一的障碍是它给每对两次。 So, the trick is to note that in one of the two rows, the id1
value is smaller than the id2
value. 因此,诀窍是要注意在两行之一中, id1
值小于id2
值。 As a possibly beneficial side-effect, this eliminates anyone who likes themself. 作为可能有益的副作用,这消除了任何喜欢自己的人。
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
Now to tidy it up with names: 现在用名称整理一下:
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
is mnemonic for 'pairs'. p
是“成对”的助记符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.