获取各区域活动最频繁日期及占比的SQL查询优化需求
解决方案
可以通过CTE(公共表表达式)分步计算,先统计每个区域各星期几的活动数量,同时计算区域总活动数,再筛选出每个区域活动数最多的日期并计算占比:
WITH area_daily_stats AS ( SELECT a.location, TO_CHAR(h.started_at, 'FMDay') AS day_of_week, COUNT(h.id) AS daily_count, SUM(COUNT(h.id)) OVER (PARTITION BY a.location) AS total_area_happenings FROM areas a JOIN happenings h ON a.id = h.primary_area_id WHERE h.started_at BETWEEN {{start}} AND {{end}} GROUP BY a.location, TO_CHAR(h.started_at, 'FMDay') ), ranked_days AS ( SELECT location, day_of_week AS most_frequent_day, ROUND((daily_count::FLOAT / total_area_happenings) * 100, 2) || '%' AS percentage, RANK() OVER (PARTITION BY location ORDER BY daily_count DESC) AS rnk FROM area_daily_stats ) SELECT location, most_frequent_day, percentage FROM ranked_days WHERE rnk = 1;
关键说明:
- 使用
TO_CHAR(h.started_at, 'FMDay'):避免默认'Day'格式带来的尾部空格(默认会把短星期名补空格到9位,FMDay会输出无填充的完整星期名称,如Saturday)。 SUM(COUNT(h.id)) OVER (PARTITION BY a.location):窗口函数直接计算每个区域的总活动数,无需额外子查询关联。RANK() OVER (...):对每个区域内的日期按活动数排序,筛选出排名第一的记录(如果有多个日期活动数相同,会返回多条;若要强制只取一条,可改用ROW_NUMBER())。- 占比计算:将整数转换为FLOAT后计算比例,乘以100保留两位小数并拼接百分号。
样本数据验证:
代入你提供的样本数据,将{{start}}设为'2023-02-18'、{{end}}设为'2023-02-20',查询结果与期望一致:
location | most_frequent_day | percentage ----------------------------------------- Wandsworth| Saturday | 66.67% Bexley | Monday | 100.00%
内容的提问来源于stack exchange,提问作者DavidM
相关产品推荐
相关产品推荐

