PostgreSQL 通过 GROUP BY 删除重复项

Vis*_*seo 5 sql postgresql distinct sql-order-by greatest-n-per-group

我想打印一个人的最后一条消息,但每个人只应打印他的最新消息。我使用 PostgreSQL 10。

+-----------+----------+--------------+
| name      |   body   |  created_at  |
+-----------+----------+--------------+
| Maria     | Test3    |  2017-07-07  |
| Paul      | Test5    |  2017-06-01  |
+-----------+----------+--------------+
Run Code Online (Sandbox Code Playgroud)

我已经用下面的 SQL 查询尝试过,这给了我确切的结果,但不幸的是,人们在其中加倍了。

+-----------+----------+--------------+
| name      |   body   |  created_at  |
+-----------+----------+--------------+
| Maria     | Test3    |  2017-07-07  |
| Paul      | Test5    |  2017-06-01  |
+-----------+----------+--------------+
Run Code Online (Sandbox Code Playgroud)
+-----------+----------+--------------+
| name      |   body   |  created_at  |
+-----------+----------+--------------+
| Maria     | Test1    |  2016-06-01  |
| Maria     | Test2    |  2016-11-01  |
| Maria     | Test3    |  2017-07-07  |
| Paul      | Test4    |  2017-01-01  |
| Paul      | Test5    |  2017-06-01  |
+-----------+----------+--------------+
Run Code Online (Sandbox Code Playgroud)

我尝试使用 DISTINCT 删除重复项,但不幸的是我收到此错误消息:

SELECT * FROM messages 
WHERE receive = 't'
GROUP BY name
ORDER BY MAX(created_at) DESC
Run Code Online (Sandbox Code Playgroud)
ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions LINE 1: SELECT DISTINCT ON (name) * FROM messages ^ : SELECT DISTINCT ON (name) * FROM messages WHERE receive = 't' GROUP BY name ORDER BY MAX(created_at) DESC
Run Code Online (Sandbox Code Playgroud)

您对我如何解决这个问题有什么想法吗?

GMB*_*GMB 4

您将使用DISTINCT ON如下:

SELECT DISTINCT ON (name) * 
FROM messages 
WHERE receive = 't'
ORDER BY name, created_at DESC
Run Code Online (Sandbox Code Playgroud)

那是:

  • GROUP BY不需要任何条款

  • 中列出的列DISTINCT ON(...)必须出现在ORDER BY子句的前面

  • ...后面是应该用来打破组的列(这里是created_at

请注意,查询的结果distinct on始终按子句中的列排序(因为这种排序用于标识应保留哪些行)。

如果您想更好地控制排序顺序,则可以使用窗口函数:

SELECT *
FROM (
    SELECT m.*, ROW_NUMBER() OVER(PARTITION BY name ORDER BY created_at DESC) rn
    FROM messages m
    WHERE receive = 't'
) t
WHERE rn = 1
ORDER BY created_at DESC
Run Code Online (Sandbox Code Playgroud)