MySQL - 如何在 JOIN 中使用相关子查询

Posted

技术标签:

【中文标题】MySQL - 如何在 JOIN 中使用相关子查询【英文标题】:MySQL - How to use a correlated subquery inside a JOIN 【发布时间】:2020-09-27 04:12:12 【问题描述】:

我有两张桌子,ObjectsEvents

Objects 的结构如下:

ID | Password
-------------
0  | aaaa
1  | bbbb

事件的结构如下:

Object | Date       | Type
--------------------------
0      | 2020-06-01 | 0
0      | 2020-06-02 | 1

我想要实现的是:对于每个 ID,获取最后一个关联的事件类型。在上面的示例中,对象0 将与1 相关联,因为12020-06-02 上最后一个事件的类型。此外,当一个对象没有任何事件时,将1 关联到它。

我尝试为每个对象排序事件,这样我就可以使用查询加入我的对象信息:

SELECT ID, IFNULL(e.Type, 1)
FROM objects o
LEFT JOIN (
    SELECT e.Object, e.Date, e.Type
    FROM events e
    WHERE e.Object = o.ID
    ORDER BY e.Date DESC
    LIMIT 1
) AS e ON e.Object = o.ID

由于o.ID 未知,它不起作用,但我真的想不出任何其他解决方案。因此我的问题是:如何在连接表的条件内使用外部表的属性?

如果有不清楚的地方请告诉我,谢谢。

【问题讨论】:

您对此样本数据的预期输出是什么? 我只需要 ID 和类型。这就是我使用SELECT ID, IFNULL(e.Type, 1)的原因。 【参考方案1】:
SELECT ID, IFNULL(e.Type, 1)
FROM objects o
LEFT JOIN (
    SELECT e.Object, max(e.Date), e.Type
    FROM events e
    GROUP BY e.Date DESC
) AS e ON e.Object = o.ID

【讨论】:

不,因为这只会返回加入其对象信息的最新事件,而我需要每个对象的最新事件。 啊,现在我明白了。然后您需要聚合子查询中的行。类似于修改后的答案【参考方案2】:

你可以试试这样的:

SELECT o.id, max(e.date) AS date, e.type
FROM objects o
INNER JOIN events e ON(o.id = e.object)
GROUP BY o.id, e.type
ORDER BY e.date DESC;

输出

+------+------------+------+
| id   | date       | type |
+------+------------+------+
|    0 | 2020-06-02 |    1 |
|    0 | 2020-06-01 |    0 |
+------+------------+------+

希望这会有所帮助。

【讨论】:

【参考方案3】:

Events 中使用NOT EXISTS 仅返回按日期的最后一行:

SELECT ID, IFNULL(e.Type, 1) Type
FROM Objects o
LEFT JOIN (
    SELECT e.Object, e.Type
    FROM Events e
    WHERE NOT EXISTS (
      SELECT 1 FROM Events
      WHERE Object = e.Object AND Date > e.Date 
    ) 
) AS e ON e.Object = o.ID

或:

SELECT 
  o.ID, 
  IFNULL((SELECT e.Type FROM Events e WHERE e.Object = o.ID ORDER BY e.Date DESC LIMIT 1), 1) Type
FROM Objects o

请参阅demo。 结果:

> ID | Type
> -: | ---:
>  0 |    1
>  1 |    1

【讨论】:

【参考方案4】:

如果您有版本 8 或更高版本,您可以使用 row_number() 函数计算最后一行

select * from
(
select id,coalesce(type,1) type,coalesce(date,date(now())) as dt,
         row_number() over (partition by o.id order by coalesce(date,date(now())) desc) rn
from  objects o
left join events e on e.object = o.id
order by o.id,dt desc
) s
where rn = 1;

【讨论】:

以上是关于MySQL - 如何在 JOIN 中使用相关子查询的主要内容,如果未能解决你的问题,请参考以下文章

Mysql join with subquery join 使用相关名称

如何在不使用 Join 的情况下处理引用其他表的相关子查询的问题

Mysql JOIN 子查询

为什么MySQL不推荐使用子查询和join

MySQL高级第八篇:关联查询子查询和排序相关优化

MySQL 子查询与 LIMIT 与 JOIN