【问题标题】:Inner join in self join - MySql自连接中的内连接 - MySql
【发布时间】:2018-10-23 17:42:48
【问题描述】:

在 Stack Overflow 上提出了以下问题:

“我需要在这个表上使用 Self Join。

+------------+------+--------+
| Country    | Rank |  Year  |
+------------+------+--------+
|France      |  55  |  2000  |
+------------+------+--------+
|Canada      |  30  |  2000  |
+------------+------+--------+ 
|Liberia     |  59  |  2001  |
+------------+------+--------+ 
|Turkey      |  78  |  2000  |
+------------+------+--------+ 
|Japan       |  65  |  2003  |
+------------+------+--------+
|Romania     |  107 |  2001  |
+------------+------+--------+

我需要使用自我加入来获取与土耳其相同年份的国家/地区。仅显示国家和年份。”

在选择正确的答案中,推荐的查询之一是:

SELECT DISTINCT a.Country, a.Year 
FROM table1 AS a 
INNER JOIN table1 AS b 
   on a.Year=b.Year 
  and b.Country='Turkey';

我没有收到此查询。不是a.Year=b.Year 总是正确的——因为两张表都是一样的吗?那么使用它有什么需要呢? 而且上面的查询不是只返回国内的'Turkey'吗?

如果我错了,请帮助我理解。

非常感谢!

【问题讨论】:

  • 通过查询添加您的预期输出以及您将应用什么条件
  • a.Year=b.Year 是一个连接条件。它并不总是正确的,因为表格中的每一年都与其他年份不同。查询应返回法国、加拿大和土耳其。你可以随时just test run and see
  • Explanation of self-joins的可能重复
  • DISTINCT 只有在表可以包含土耳其的多条记录时才有意义。请参阅蒂姆的回答;无论如何都可以使用子查询而不是联接来解决此类任务。
  • 这是一个常见问题解答,您在问 select 语句是如何工作的。请阅读How to Ask 和向下投票箭头鼠标悬停文本。 (条件告诉您要从交叉连接中保留哪些行——您可以从每个输入的一行中创建的每一行中保留哪些行。)PS Re self-join.

标签: mysql self-join


【解决方案1】:

不是说 a.Year=b.Year 总是正确的吗?

没有。将此视为首先获取 A 和 B 的笛卡尔积(将 a 的所有行与 b 的所有行匹配),然后选择 a 的年份和 B 的年份相同的那些行。这会产生两个国家相同年份的数据。

使用这些数据,我们可以进一步确定与土耳其结对的国家。

这就是这个查询正在做的事情。

【讨论】:

    【解决方案2】:

    如果您必须在此处使用自联接,请尝试以下操作:

    SELECT t1.Country, t1.Year
    FROM table1 t1
    INNER JOIN table1 t2
        ON t1.Year = t2.Year AND t2.Country = 'Turkey';
    

    Demo

    这不是我认为的自联接查询的典型候选者。在这种情况下,第二个(右)表只是代表土耳其的年份。

    我宁愿只使用子查询:

    SELECT Country, Year
    FROM table1
    WHERE Year = (SELECT Year FROM table1 WHERE Country = 'Turkey');
    

    请注意,这也会将土耳其本身包括在结果集中。如果您不想也想看到土耳其,那么我们可以在WHERE 子句中添加另一个条件:

    SELECT Country, Year
    FROM table1
    WHERE Year = (SELECT Year FROM table1 WHERE Country = 'Turkey') AND Country <> 'Turkey';
    

    【讨论】:

    • 超越了“需要使用自联接”语句,问题更多的是询问联接条件的含义,而不是重写为子查询。对我来说,作为一个自我加入似乎已经足够好了。
    • @danblack 我不同意,我宁愿继承子查询代码。为什么?因为很明显我们正在根据土耳其的年份过滤表格。
    • @danblack:我同意问题在于(自我)加入实际上是如何工作的。但是这样的任务真的不应该用自连接来解决,而是用子查询来解决是正确的。所以蒂姆指出这一点很好,因为 OP 显然是初学者。条件属于WHERE 子句。这使查询更具可读性。
    【解决方案3】:

    请记住,您要加入WHERE 子句和ON 子句总是一次引用每个表的特定行。此伪代码显示了连接中实际发生的情况:

    foreach a = row of table1
      if a.country = 'Turkey' then
        foreach b = row of table1
          if b.year = a.year then
            keep the joined row
          endif
        endloop
      endif
    endloop
    

    (DBMS 可能会使用另一种匹配记录的方法。但您可以像上面那样想象。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多