简体   繁体   English

如何编写这种复杂的自我联接

[英]How to write this complex self join

I have two tables with given fields 我有给定字段的两个表

  1. HighSchooler 高中生

    • name 名称
    • grade 年级
    • id ID
  2. Likes 喜欢

    • id1 id1
    • id2 id2

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;

please see fiddle : 请看小提琴

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表中,以获取两个人的名字。

Step 1 Pairs of IDs where each likes the other 步骤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;

This gives the list of pairs of IDs where each likes the other. 这给出了彼此相似的ID对的列表。

Step 2 Pairs of IDs where each likes the other without repeats 步骤2一对ID,每个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

Step 3 Pairs of Names where each likes the other 步骤3一对互相喜欢的名字

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM