【问题标题】:Rows count without distinct行数没有区别
【发布时间】:2015-07-13 19:53:05
【问题描述】:

我有这个问题:

SELECT DISTINCT ON (pair) *,
    CASE WHEN sender_id<recipient_id
      THEN (sender_id,recipient_id)
      ELSE (recipient_id,sender_id)
    END AS pair FROM "messages" WHERE 
    ((recipient_id = 6 and recipient_delete = false) or 
    (sender_id = 6 and sender_delete = false))  
    GROUP BY messages.id
    ORDER BY  pair, created_at, unread_count DESC

带来用户对话的最新消息(用户收件箱)。

现在我需要显示每个对话的未读消息总数,“已打开”表中有一个标志,表示消息是否未读。

这是我为它写的查询:

SELECT DISTINCT ON (pair) *,
    CASE WHEN sender_id<recipient_id
      THEN (sender_id,recipient_id)
      ELSE (recipient_id,sender_id)
    END AS pair, COUNT(messages.opened= false) AS unread_count FROM "messages" WHERE 
    ((recipient_id = 6 and recipient_delete = false) or 
    (sender_id = 6 and sender_delete = false))  
    GROUP BY messages.id
    ORDER BY  pair, created_at, unread_count DESC

但即使有超过 2 或 3 条消息,它也会显示计数为 1(我猜这是因为 Distinct)。

有什么想法吗?

如果您想知道为什么我们有用户CASE WHEN 功能,请查看此question

【问题讨论】:

    标签: mysql postgresql


    【解决方案1】:

    我有点困惑,因为您的逻辑似乎会带来 最早 消息而不是最新消息。

    虽然distinct on 很强大,但我不确定你是否能轻易得到你想要的。我的倾向是改用窗口函数:

    SELECT m.*
    FROM (SELECT m.*,
                 (CASE WHEN sender_id < recipient_id
                       THEN (sender_id, recipient_id)
                       ELSE (recipient_id, sender_id)
                  END) AS pair,
                 ROW_NUMBER() OVER (PARTITION BY (CASE WHEN sender_id < recipient_id
                                                       THEN (sender_id, recipient_id)
                                                       ELSE (recipient_id, sender_id)
                                                  END)
                                    ORDER BY created_at, unread_count DESC
                                   ) as seqnum,
                 SUM(CASE WHEN m.opened = false THEN 0 ELSE 1 END) OVER
                     (PARTITION BY (CASE WHEN sender_id < recipient_id
                                         THEN (sender_id, recipient_id)
                                         ELSE (recipient_id, sender_id)
                                    END)
                     ) as NumUnopened
          FROM "messages" m
          WHERE ((recipient_id = 6 and recipient_delete = false) or 
                 (sender_id = 6 and sender_delete = false))  
         ) t
    WHERE seqnum = 1;
    

    【讨论】:

    • 最早消息不是最新消息有什么区别。另请注意,我需要每个对话的未读消息计数,而不是总数。
    • 我收到此错误:错误:列“m.id”必须出现在 GROUP BY 子句中或用于聚合函数中
    【解决方案2】:

    在您的查询中选择字段“messages.opened”(别名messages_opened),然后像这样包围它们:

    选择计数(messages_opened) FROM (... [your query] ) as A 其中 A.messages_opened = false

    查询示例:

    将@table 声明为表 ( messageid INT, 发件人 INT, 收件人 INT ) 插入@table (消息ID, 发件人ID, 收件人ID) 价值观(1, 10, 20), (2, 10, 20), (3, 11, 20), (4, 11, 20), (5, 10, 20) 选择 Count(messageid) 作为 countOfMessages, 发件人ID, 收件人ID 来自@表 按发件人ID分组, 收件人ID

    【讨论】:

    • 我想要每个对话的未读消息计数,而不是总数。很抱歉造成混乱..
    • 然后添加一个“分组依据”并计算每个对话。像这样:select COUNT(messageId) as countOfMessages, senderID, recipientId from @table group by senderID,recipientId
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-09
    • 2022-01-06
    • 1970-01-01
    • 2019-06-04
    • 2019-08-11
    • 2012-01-13
    相关资源
    最近更新 更多