PostgreSQL:连接查询获取行数及按用户审计数排序统计
解决按审计记录数量排序的用户统计问题
咱们先捋清楚你原查询的问题:你现在的语句是把学校、用户和每条审计记录做了关联,所以返回的是每条审计记录对应的用户信息,而不是每个用户的审计记录总数,而且排序逻辑也不是你要的按审计数量排序,而是按用户创建时间倒序,这完全不符合你的需求~
下面给你两种场景的正确查询方案:
场景1:只统计有审计记录的用户
如果只需要展示那些有过操作审计的用户,用这个查询,核心是通过GROUP BY按用户维度分组,再用COUNT统计每个用户的审计记录数,最后按统计数倒序:
SELECT s.user_created, u.first_name, u.last_name, u.email, COUNT(a.audit_id) AS audit_count -- 用审计表主键统计,避免统计NULL行 FROM cbrain_school s INNER JOIN ugrp_user u ON s.user_created = u.user_id INNER JOIN audit a ON u.user_id = a.user_id GROUP BY s.user_created, u.first_name, u.last_name, u.email ORDER BY audit_count DESC;
场景2:包含没有审计记录的用户(审计数显示为0)
如果想把那些从未产生过审计记录的用户也列出来(审计数显示0),只需要把和audit表的关联改成LEFT JOIN就行,这样没有审计记录的用户也会被保留,统计数自然就是0:
SELECT s.user_created, u.first_name, u.last_name, u.email, COUNT(a.audit_id) AS audit_count FROM cbrain_school s INNER JOIN ugrp_user u ON s.user_created = u.user_id LEFT JOIN audit a ON u.user_id = a.user_id GROUP BY s.user_created, u.first_name, u.last_name, u.email ORDER BY audit_count DESC;
额外小提示
- 分组字段要注意:严格SQL模式下,
GROUP BY必须包含所有SELECT里没被聚合的字段,所以这里把用户的几个标识字段都加进去了 - 如果需要在审计数相同的情况下,再按用户创建时间排序,可以把
ORDER BY改成audit_count DESC, u.created_time DESC - 用
COUNT(a.audit_id)比COUNT(*)更准确,因为LEFT JOIN后无审计记录的行里,a表的字段都是NULL,COUNT会忽略这些NULL值,刚好得到0的统计结果
内容的提问来源于stack exchange,提问作者Geo Thomas




