【问题标题】:How to join the first and the last record from table using MySQL?如何使用 MySQL 连接表中的第一条和最后一条记录?
【发布时间】:2020-12-24 13:53:29
【问题描述】:

我有 2 张桌子。第一个表是-products,第二个是revisions。
通过 product.id = revisions.revisionable_id 加入。 我需要将产品作为 1 条记录并作为第一个修订版(created_at 字段 (2017))和最后一个修订版(created_at (2020))加入,并获得如下内容:
产品名称、Revision_2017、Revision_2020
请帮忙。
产品

+----+-------+
| id | name  |
+----+-------+
|  1 | Tesla |
+----+-------+

修订

+----+-----------------+------------+----------+---------+
| id | revisionable_id | created_at | metadata | user_id |
+----+-----------------+------------+----------+---------+
|  1 |               1 | 2017-01-01 | {}       |       5 |
|  2 |               1 | 2018-01-01 | {}       |       5 |
|  3 |               1 | 2019-01-01 | {}       |       5 |
|  4 |               1 | 2020-01-01 | {}       |       5 |
+----+-----------------+------------+----------+---------+

想要的结果:

+-------------+---------------+---------------------+-------------------+--------------------+------------------+
| Products.id | Products.name | revFirst.created_at | revFirst.metadata | revLast.created_at | revLast.metadata |
+-------------+---------------+---------------------+-------------------+--------------------+------------------+
|           1 | Tesla         | 2017-01-01          | {}                | 2020-01-01         | {}               |
+-------------+---------------+---------------------+-------------------+--------------------+------------------+

【问题讨论】:

  • 请以表格文本的形式提供示例数据和所需结果。
  • 添加了想要的结果

标签: mysql sql datetime subquery sql-order-by


【解决方案1】:

一个选项使用窗口函数,在 MySQL 8.0 中可用:

select p.*,
    max(case when rn_asc  = 1 then created_at end) as first_created_at,
    max(case when rn_asc  = 1 then metadata   end) as first_metadata,
    max(case when rn_desc = 1 then created_at end) as last_created_at,
    max(case when rn_desc = 1 then metadata   end) as last_metadata
from product p
left join (
    select r.*, 
        row_number() over(partition by product_id order by created_at) rn_asc,
        row_number() over(partition by product_id order by created_at desc) rn_desc
    from revisions r
) r on r.product_id = p.id and 1 in (r.rn_asc, r.rn_desc)
group by p.id

我无法准确判断 revisions 中的哪一列与产品 id 相关(id?revisionable_id?)所以我改为将该列称为 product_id

在最新版本的 MySQL (8.0.13) 中,两个横向连接可能是一个不错的方法:

select p.*, r1.*, r2.*
from product p
left join lateral (
    select created_at as first_created_at, metadata as first_metadata
    from revisions r 
    where r.product_id = p.id
    order by created_at limit 1
) r1 on true
left join lateral (
    select created_at as last_created_at, metadata as last_metadata
    from revisions r 
    where r.product_id = p.id
    order by created_at desc limit 1
) r2 on true

在早期版本中,我会使用几个子查询:

select p.*,
    (
        select r.created_at
        from revisions r 
        where r.product_id = p.id
        order by r.created_at limit 1
    ) as first_created_at,
    (
        select r.metadata 
        from revisions r 
        where r.product_id = p.id
        order by r.created_at limit 1
    ) as first_metadata
    (
        select r.created_at
        from revisions r 
        where r.product_id = p.id
        order by r.created_at desc limit 1
    ) as last_created_at,
    (
        select r.metadata 
        from revisions r 
        where r.product_id = p.id
        order by r.created_at desc limit 1
    ) as last_metadata
from product p

为了提高性能,您需要以下索引:

revisions(product_id, created_at, metadata);
revisions(product_id, created_at desc, metadata);

【讨论】:

  • 按product.id = revisions.revisionable_id 加入。感谢您的回答,正在尝试
  • 我使用的是 5.7 版((你的方法不会有帮助,无论如何谢谢
  • @АнатолийКостяков:好的,然后看我的更新。
  • 不知道 MySQL 实现了横向连接。只为那个 +1。
  • @TheImpaler:在我看来,这是 MySQL 的一大进步!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 2012-05-15
相关资源
最近更新 更多