Igo*_*gor 6 mysql postgresql greatest-n-per-group
我确定这是一个简单的问题,我想它被问了很多次,但我无法从其他答案中弄清楚,抱歉。
我使用最新版本的 PostgreSQL 和 MySQL。我有2张桌子:
CREATE TABLE authors (
id INT,
name VARCHAR
)
CREATE TABLE posts (
id INT,
author_id INT,
text VARCHAR,
date DATE
)
Run Code Online (Sandbox Code Playgroud)
我需要为每个作者选择一个最新的帖子。谢谢!
更新
谢谢,这两个链接都提供了我的问题的答案,但有一些例外。以下所有查询都给出了相同的结果(顺便说一句,哪个最有效?)然后返回的结果集包含所有此类帖子。我应该如何修改这些查询返回正好每位作者一个帖子?
SELECT p1.*
FROM posts p1
LEFT JOIN posts p2 ON p1.author_id = p2.author_id AND p1.date < p2.date
WHERE p2.author_id IS NULL
ORDER BY p1.author_id;
SELECT p1.*
FROM posts p1
INNER JOIN (
SELECT author_id, MAX(date) AS max_date
FROM posts
GROUP BY author_id) p2
ON p1.author_id = p2.author_id AND p1.date = p2.max_date
ORDER BY p1.author_id;
SELECT *
FROM posts p1
WHERE date = (SELECT MAX(p2.date)
FROM posts p2
WHERE p1.author_id = p2.author_id)
ORDER BY author_id;
SELECT * FROM (
SELECT author_id, MAX(date) date
FROM posts GROUP BY author_id
) p1 INNER JOIN posts p2 USING (author_id, date)
ORDER BY author_id;
Run Code Online (Sandbox Code Playgroud)
ype*_*eᵀᴹ 19
如果您的目标是以最高效率进行查询,那么上述查询都不是最好的。至少并不总是如此。
效率取决于很多不同的东西,比如特定的 DBMS、特定的版本(不同版本对优化器和可用语法有不同的改进)、列的类型、可用的索引、表的大小和值的分布、服务器运行的硬件,配置设置等。
您应该始终测试在您的表上编写查询的各种不同方式,以及您希望在生产中使用的大小和分布,以及您的硬件和配置设置,以决定应该保留哪些查询重写。
这种特定类型的查询通常被称为greatest-n-per-group(甚至有一个标签!)并且在某些假设下,编写它们的多种方法之一在 MySQL 和 PostgreSQL 中通常非常有效。它使用LATERALPostgres 中的连接,该连接在 9.3+ 版本中可用(在 SQL Server 术语中CROSS/OUTER APPLY)以及在 MySQL 中模拟此连接。
假设是作者的数量(我们分组的属性)与帖子的数量(我们应用分组依据的表)相比很小。如果有一个索引或一个表来查找所有不同的author_id值,并在posts表上为 group by 提供一个附加索引,那也是最好的。
这个对每组最大 n 次问题的解决方案也符合您对关系的要求,因为它始终为每组返回一个结果。如果要得到准确的其中一个(的并列)将返回时,ORDER BY在子查询中可以修改(以ORDER BY pi.date DESC, pi.id DESC或ORDER BY pi.date DESC, a.name为例)。
在 PostgreSQL 中查询:
SELECT p.*
FROM authors AS a
, LATERAL
( SELECT pi.*
FROM posts AS pi
WHERE pi.author_id = a.author_id
ORDER BY pi.date DESC
LIMIT 1
) AS p ;
Run Code Online (Sandbox Code Playgroud)
在 MySQL 中查询:
SELECT p.*
FROM authors AS a
JOIN posts AS p
ON p.id =
( SELECT pi.id
FROM posts AS pi
WHERE pi.author_id = a.author_id
ORDER BY pi.date DESC
LIMIT 1
) ;
Run Code Online (Sandbox Code Playgroud)
有用的索引posts (author_id, date, id)对于 MySQL 和/或posts (author_id, date DESC)对于 Postgres是打开的。
不用再说了,但在使用上述任何一个之前,它们应该在您的环境中进行测试,并针对查询的所有许多其他版本/重写进行交叉测试。例如,在 Postgres 中,该DISTINCT ON语法可以在 9.3 之前的版本中使用。结果查询比 更紧凑,LATERAL并且在不同的数据分布下可能更有效。询问:
SELECT DISTINCT ON (author_id) p.*
FROM posts AS p
ORDER BY p.author_id,
p.date DESC ;
Run Code Online (Sandbox Code Playgroud)