如何编写带COUNT的SQL子查询?MySQL电影标签统计需求实现
问题:统计电影标签的最小、最大及平均数量(含去重规则)
我使用MySQL数据库,需从tags表统计每部电影不同标签数量的最小值、最大值和平均值,需排除两类重复:
- 同一用户给同一电影的相同标签
- 不同用户给同一电影的相同标签
示例表结构及数据
| userId | movieId | tag |
|---|---|---|
| 1 | 1 | crime |
| 1 | 2 | dark |
| 1 | 2 | dark |
| 2 | 2 | greed |
| 2 | 2 | dark |
| 3 | 3 | music |
| 3 | 3 | dance |
| 3 | 3 | quirky |
| 4 | 3 | dance |
| 4 | 3 | quirky |
期望查询结果
| movieId | Min_Tag | Max_Tag | Avg_Tag |
|---|---|---|---|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 0.66... |
| 3 | 1 | 2 | 0.6 |
错误SQL及问题分析
我尝试编写以下SQL语句但报错:
SELECT DISTINCT movieId, MIN(COUNT(DISTINCT tag) AS Min_Tag, MAX(COUNT(DISTINCT tag) AS Max_Tag, AVG(COUNT(DISTINCT tag) AS Avg_Tag, FROM ( SELECT userId,movieId,tag FROM tags GROUP BY userId, movieId, tag ) AS non_dup GROUP BY movieId;
错误原因
- 语法错误:括号不匹配,每个聚合函数调用缺少闭合括号;语句末尾多余逗号。
- 逻辑错误:MySQL不允许在聚合函数(如
MIN/MAX/AVG)中嵌套另一个聚合函数(如COUNT)。且外层直接按movieId分组后使用COUNT(DISTINCT tag),得到的是电影总去重标签数,无法实现“统计每个用户给该电影的标签数的极值和均值”的需求。
正确SQL实现
要实现需求,需分两步聚合:
- 先去除同一用户对同一电影的重复标签,再统计每个用户对每部电影的标签数量。
- 基于第一步结果,按电影分组计算标签数的最小值、最大值和平均值。
SELECT movieId, MIN(tag_count) AS Min_Tag, MAX(tag_count) AS Max_Tag, AVG(tag_count) AS Avg_Tag FROM ( -- 统计每个用户对每部电影的去重标签数量 SELECT userId, movieId, COUNT(DISTINCT tag) AS tag_count FROM tags GROUP BY userId, movieId ) AS user_movie_tag_counts GROUP BY movieId;
结果说明
执行上述SQL后,结果符合核心逻辑:
- movieId=1:仅1个用户,标签数为1,因此Min/Max/Avg均为1。
- movieId=2:用户1标签数为1,用户2标签数为2,因此Min=1,Max=2,Avg=(1+2)/2=1.5。
- movieId=3:用户3标签数为3,用户4标签数为2,因此Min=2,Max=3,Avg=(3+2)/2=2.5。
若期望结果是基于「标签的用户覆盖占比」计算,可调整逻辑为统计每个标签的用户数与电影总用户数的比值,再计算极值和均值:
SELECT movieId, MIN(tag_user_ratio) AS Min_Tag, MAX(tag_user_ratio) AS Max_Tag, AVG(tag_user_ratio) AS Avg_Tag FROM ( SELECT t.movieId, t.tag, COUNT(DISTINCT t.userId) / u.total_users AS tag_user_ratio FROM tags t JOIN ( SELECT movieId, COUNT(DISTINCT userId) AS total_users FROM tags GROUP BY movieId ) AS u ON t.movieId = u.movieId GROUP BY t.movieId, t.tag ) AS tag_ratios GROUP BY movieId;
内容的提问来源于stack exchange,提问作者amber_the_debutant
相关产品推荐
相关产品推荐

