SQL 获取具有与特定值匹配的最新关联的记录

Posted

技术标签:

【中文标题】SQL 获取具有与特定值匹配的最新关联的记录【英文标题】:SQL get records having latest association matching a specific value 【发布时间】:2020-09-13 23:56:33 【问题描述】:

上下文

使用 PostgreSQL,我正在存储 articles 及其关联的 events。为了示例,以下是 2 个表的简单结构:

文章表

+----+-----------+-----------------------+
| ID |   title   |      description      |
+----+-----------+-----------------------+
|  1 | article 1 | article 1 description |
|  2 | article 2 | article 2 description |
|  3 | article 3 | article 3 description |
|  4 | article 4 | article 4 description |
|  5 | article 5 | article 5 description |
+----+-----------+-----------------------+

事件表

+-----+-----------+--------------+----------------+--------------+
| ID  |   name    | eventable_id | eventable_type | created_at   |
+-----+-----------+--------------+----------------+--------------+
|  1  | validated |            1 | Article        | 2020-05-10   |
|  2  | reported  |            1 | Article        | 2020-05-11   |
|  3  | reported  |            2 | Article        | 2020-05-10   |
|  4  | reported  |            2 | Article        | 2020-05-11   |
|  5  | reported  |            2 | Article        | 2020-05-12   |
|  6  | reported  |            3 | Article        | 2020-05-20   |
|  7  | validated |            3 | Article        | 2020-05-21   |
|  8  | reported  |            4 | Article        | 2020-05-12   |
|  9  | moved     |            4 | Article        | 2020-05-13   |
|  10 | reported  |            4 | Article        | 2020-05-14   |
|  11 | moved     |            5 | Article        | 2020-05-13   |
|  12 | moved     |            5 | Article        | 2020-05-14   |
+-----+-----------+--------------+----------------+--------------+

问题

在这里,我需要能够获取所有articles,它们的最新eventsreported

所以例如,按照上面的数据,我们只能得到:

article 1:因为一直是validated,然后是reported article 2:因为它只是reported article 4:因为一直是moved然后是reported(同第1条)

如你所见:

article 3:不应该返回,因为它的最新事件是validatedarticle 5:不应该返回,因为它的最新事件是moved

我可以轻松找到所有articlesreported 事件。但是如何让有最新活动的人成为reported

这是我到目前为止所做的尝试但没有成功:

SELECT *
FROM articles a
INNER JOIN (
    SELECT *
    FROM events
    WHERE name = 'reported'
    ORDER BY created_at
    LIMIT 1
) AS e ON e.moderable_id = a.id AND e.moderable_type = 'Article'

我们目前有:

459 892 articles 62 074 events

【问题讨论】:

你试过查询了吗? 注意:你的事件似乎比文章少? @wildplasser 是的,因为并非所有文章都有事件 【参考方案1】:

您可以使用相关子查询进行过滤:

select a.*
from articles a
where 
    (
        select e.name
        from events e
        where e.eventable_id = a.id and e.eventable_type = 'Article'
        order by created_at desc 
        limit 1
    ) = 'reported'

我们也可以用横向连接来表达:

select a.*
from articles a
inner join lateral (
    select e.name 
    from events 
    where e.eventable_id = a.id and e.eventable_type = 'Article'
    order by created_at desc 
    limit 1
)  x on x.status = 'reported'

【讨论】:

非常感谢,您的两个示例实际上都在工作(我需要使用更大的数据运行更多测试以确保这一点)。我有一个问题:这些查询中哪个最快?我们目前有 459 891 articles 和 62 074 events @lkartono:我认为有相当多的等价物(并且可能,它们产生相同的执行计划)。不过,您可能希望根据您的数据评估性能。 events(eventable_id, eventable_type, created_at, name) 上的索引可能会有所帮助。 感谢有关索引的提示,从 21 秒缩短到 118 毫秒 :)

以上是关于SQL 获取具有与特定值匹配的最新关联的记录的主要内容,如果未能解决你的问题,请参考以下文章

获取具有与特定模式匹配的连接列的行

获取与特定值匹配的 JSON 对象

SQL 获取第一个匹配结果

匹配数组项值并将新值分配给关联数组

匹配的关联和没有关联的记录 cakephp 3

SQL - 如果一条记录具有特定值,则仅获取该记录,否则获取全部