为什么在 where 子句中使用相关查询进行查询时,结果集中没有相似的 id

Why no similar ids in the results set when query with a correlated query inside where clause

我有一个 table 包含列 id、名字、姓氏、创建(日期)。

我有一个 table 如下所示:

ID | Forename | Surname | Created
---------------------------------
 1 | Tom      | Smith   | 2008-01-01
 1 | Tom      | Windsor | 2008-02-01
 2 | Anne     | Thorn   | 2008-01-05
 2 | Anne     | Baker   | 2008-03-01
 3 | Bill     | Sykes   | 2008-01-20

Basically, I want this to return the most recent name for each ID, so it would return:

ID | Forename | Surname | Created
---------------------------------
 1 | Tom      | Windsor | 2008-02-01
 2 | Anne     | Baker   | 2008-03-01
 3 | Bill     | Sykes   | 2008-01-20

我通过这个查询得到了想要的结果。

SELECT id, forename, surname, created
FROM name n
WHERE created = (SELECT MAX(created)
                              FROM name
                              GROUP BY id
                              HAVING id = n.id);

我得到了我想要的结果,但我不明白为什么 IDS 在结果集中没有被重复。我对相关子查询的理解是它从外部查询 table 和内部子查询 运行 中获取一行。当 ids 在外部查询中重复时,它不应该重复 "id" 吗?谁能给我解释一下幕后到底发生了什么?

首先,您的子查询不需要 GROUP BY。更常见的写法是:

SELECT n.id, n.forename, n.surname, n.created
FROM name n
WHERE n.created = (SELECT MAX(n2.created)
                   FROM name n2
                   WHERE n2.id = n.id
                  );

您应该养成限定 所有 列引用的习惯,尤其是当您的查询有多个 table 引用时。

我想你是在问为什么这行得通。好吧,外部查询中的每一行都针对条件进行了测试。条件是:"is my created the same as the maximum created for all rows in the name table with the same id"。在您的数据中,每个 id 只有一行符合该条件,因此 id 不会重复。

您还可以考虑通过 created 与 max(created) 列值连接表:

SELECT n.id, n.forename, n.surname, n.created
  FROM name n
  RIGHT JOIN ( SELECT id, MAX(created) as created FROM name GROUP BY id ) t
    ON n.created = t.created;

或使用 IN 运算符:

SELECT id, forename, surname, created
  FROM name n
 WHERE ( id, created ) IN (SELECT id, MAX(created)
                             FROM name
                            GROUP BY id );

或在子查询中使用 EXISTSHAVING 子句:

SELECT id, forename, surname, created
  FROM name n
 WHERE EXISTS (SELECT id
                 FROM name
                GROUP BY id
                HAVING MAX(created) = n.created 
                );

Demo