18

在 PostgreSQL 中,我想一次获取每个用户并按日期排序。

这是我的查询:

SELECT id, useridx, isread, message, date
  FROM messages
 WHERE isread = 1
 GROUP BY useridx
 ORDER BY date DESC

这是一个示例数据

------------------------------------------------------
+  id  |  useridx |  isread  |  messsage |  date     +
------------------------------------------------------
   1   |  1       |  0        | Hello    |  2012-01-01    
   2   |  2       |  1        | Hi       |  2012-01-02    
   3   |  3       |  1        | Test     |  2012-01-03    
   4   |  3       |  0        | My Msg   |  2012-01-04    
   5   |  4       |  1        | sadasd   |  2012-01-05    
   6   |  4       |  1        | sdfsdfd  |  2012-01-06    
   7   |  4       |  0        | sdfsdfsd |  2012-01-07    
   8   |  5       |  0        | 5345634  |  2012-01-08
   9   |  6       |  0        | sdfdfsd  |  2012-01-09
   10  |  7       |  0        | sdfsdfsf |  2012-01-10
------------------------------------------------------

现在,我要做的是通过 useridx 对它们进行分组并按日期排序来获取此表。

预期结果

------------------------------------------------------
+  id  |  useridx |  isread  |  messsage |  date     +
------------------------------------------------------  
   6   |  4       |  1        | sdfsdfd  |  2012-01-06 
   3   |  3       |  1        | Test     |  2012-01-03  
   2   |  2       |  1        | Hi       |  2012-01-02    
------------------------------------------------------

实际结果

ERROR:  column "messages.date" must appear in the GROUP BY clause or be used in an aggregate function

我也不想分组日期。我只想用 useridx 分组并按日期 DESC 对它们进行排序。

任何帮助/想法表示赞赏!

注意:我也尝试过 Distinct。不符合我的需要或我做错了。

很困惑,被困DISTINCT ONrank()方法之间。

结论:对于在这里遇到相同问题的人,可以将其作为答案阅读。@kgrittn 和 @mu 都太短了,答案都是正确的。我将继续在我的项目中使用答案和模式,并且及时我可以理解哪个是最好的-我猜-。因此,选择其中之一并继续您的工作。你会没事的。

上次更新:有时,Distinct On 会从结果中排除一些 id。假设我有一个 id 列,我有 6 行是相同的。因此,从结果中排除它是不同的,但 rank() 只是结果。所以,使用 rank()!

4

5 回答 5

12

与 MySQL 不同,PostgreSQL 不显示未在聚合查询中聚合的列的随机数据。

解决方案在错误消息中

ERROR:  column "messages.date" must appear in the GROUP BY clause or be used in an aggregate function

这意味着您必须在选择此列时按“messages.date”列分组或使用 MIN() 或 MAX() 等聚合函数

例子:

SELECT MIN(id), useridx, isread, message, MAX(date)
FROM messages WHERE isread = 1 
GROUP BY useridx, isread, message
ORDER BY MAX(date) DESC
于 2012-04-26T22:56:54.977 回答
10

您想使用rank()窗口函数对每个useridx组中的结果进行排序,然后通过将排名结果包装在派生表中来剥离第一个:

select id, useridx, isread, message, date
from (
    select id, useridx, isread, message, date,
           rank() over (partition by useridx order by date desc) as r
    from messages
    where isread = 1
) as dt
where r = 1

这将为您提供id样本中包含 2、3 和 6 的行。当您在同一日期over有多条消息时,您可能希望在其中添加辅助排序键以始终如一地做出选择。useridx

您至少需要 PostgreSQL 8.4 (AFAIK) 才能拥有窗口函数。

于 2012-04-26T23:25:17.297 回答
5

另一种选择是使用SELECT DISTINCT ON(这与简单的非常不同SELECT DISTINCT):

SELECT *
  FROM (SELECT DISTINCT ON (useridx)
            id, useridx, isread, message, date
          FROM messages
          WHERE isread = 1
          ORDER BY useridx, date DESC) x
  ORDER BY date DESC;

在某些情况下,这可以比其他方法更好地扩展。

于 2012-04-27T12:21:49.230 回答
3

多年后,但你不能只在 FROM 子查询中订购:

SELECT m.id, m.useridx, m.isread, m.message, m.date
FROM (
   SELECT m2.id, m2.useridx, m2.isread, m2.message, m2.date 
   FROM message m2 
   ORDER BY m2.id ASC, m2.date DESC
) m
WHERE isread = 1
GROUP BY useridx

这在 PostgreSQL 9.2 中对我有用

于 2016-08-26T08:29:41.130 回答
2

您正在汇总结果。

这意味着3您将只有一行,而不是用户的 2 行。但您也为聚合行选择 id, message,isread列。PostgreSQL 应该如何传递这些数据?它应该max()是可能的值吗?也许min()

我假设您希望获得有关最新消息的数据。试试这个查询:

SELECT id, useridx, isread, message, date FROM messages
 WHERE isread = 1 AND (useridx, date) IN
  (SELECT useridx, max(date) FROM messages WHERE isread = 1 GROUP BY useridx);
于 2012-04-26T22:34:34.660 回答