You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FILTER子句不能使用聚合函数的SQL查询报错修复咨询

修复SQL查询中的聚合函数与FILTER冲突问题

错误原因

你遇到的第一个错误是因为FILTER的WHERE子句不能包含聚合函数(比如MAX(messages.created_at))。FILTER是在分组聚合前对行进行筛选,此时聚合结果还未计算生成,无法用它来作为筛选条件。

改成HAVING也不对,因为HAVING是用于分组完成后对整个分组进行过滤的关键字,不能放在FILTER语法内部,所以会触发语法错误。


修复方案:两种可行写法

方法一:使用窗口函数标记最新消息(推荐)

通过窗口函数ROW_NUMBER()给每个联系人的消息按时间倒序排名,取排名第一的即为最新消息,再结合聚合计算未读数量:

WITH ranked_messages AS (
    SELECT
        m.*,
        -- 按联系人(对方ID)分组,消息时间倒序排名,最新消息排第1
        ROW_NUMBER() OVER (
            PARTITION BY CASE WHEN m.from_id = 14 THEN m.to_id ELSE m.from_id END 
            ORDER BY m.created_at DESC
        ) AS rn
    FROM messages m
    WHERE m.from_id = 14 OR m.to_id = 14
)
SELECT
    u.id,
    u.name,
    u.avatar,
    rm.created_at AS max_created_at,
    rm.body AS last_message,
    -- 判断是否所有消息已读
    CASE WHEN COUNT(m.is_read) FILTER (WHERE m.is_read = false AND m.from_id != 14) = 0 
         THEN true ELSE false END AS is_read,
    -- 统计未读消息数量
    COUNT(m.is_read) FILTER (WHERE m.is_read = false AND m.from_id != 14) AS count_unread
FROM ranked_messages rm
JOIN users u ON 
    (rm.from_id = u.id AND u.id != 14) OR (rm.to_id = u.id AND u.id != 14)
-- 关联所有消息用于计算未读数量
LEFT JOIN messages m ON 
    ((m.from_id = 14 AND m.to_id = u.id) OR (m.to_id = 14 AND m.from_id = u.id))
WHERE rm.rn = 1 -- 只保留每个联系人的最新消息
GROUP BY u.id, u.name, u.avatar, rm.created_at, rm.body;

方法二:先获取最新消息时间,再关联取内容

先通过子查询算出每个联系人的最新消息时间,再关联消息表获取对应内容,最后聚合未读数量:

SELECT
    u.id,
    u.name,
    u.avatar,
    latest.max_created_at,
    m_last.body AS last_message,
    CASE WHEN COUNT(m.is_read) FILTER (WHERE m.is_read = false AND m.from_id != 14) = 0 
         THEN true ELSE false END AS is_read,
    COUNT(m.is_read) FILTER (WHERE m.is_read = false AND m.from_id != 14) AS count_unread
FROM (
    -- 子查询:获取每个联系人的最新消息时间
    SELECT
        CASE WHEN from_id = 14 THEN to_id ELSE from_id END AS contact_id,
        MAX(created_at) AS max_created_at
    FROM messages
    WHERE from_id = 14 OR to_id = 14
    GROUP BY contact_id
) latest
JOIN users u ON latest.contact_id = u.id
-- 关联最新消息的具体内容
JOIN messages m_last ON 
    ((m_last.from_id = 14 AND m_last.to_id = u.id) OR (m_last.to_id = 14 AND m_last.from_id = u.id))
    AND m_last.created_at = latest.max_created_at
-- 关联所有消息统计未读数量
LEFT JOIN messages m ON 
    ((m.from_id = 14 AND m.to_id = u.id) OR (m.to_id = 14 AND m.from_id = u.id))
GROUP BY u.id, u.name, u.avatar, latest.max_created_at, m_last.body;

额外优化提示

原查询中的COUNT(messages.is_read)可以简化为COUNT(*),因为FILTER已经筛选出is_read = false的行,两种写法结果一致,可读性更好。

内容的提问来源于stack exchange,提问作者BoboBoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:55:20