SQL 如何按 family_id 统计指定类型的关联行数?
结论
先确定统计范围。如果只统计 type = 'multiple' 的行,先筛选再分组;如果要统计全部关联行,并要求至少有一条 type = 'multiple',则应使用条件聚合,不能先用 WHERE 排除其他类型。
以下假设 Family.family_id 与 Types.family_fk 通过相等关系关联,统计对象是 Types 中的行。示例沿用问题中的表名 familys 和 types。如果实际表名是 Family,请替换 FROM 子句中的名称。
请求 1:恰好有一条 type = 'multiple' 的关联行
SELECT f.family_id, COUNT(*) AS multiple_count
FROM familys f
JOIN types it
ON it.family_fk = f.family_id
WHERE it.type = 'multiple'
GROUP BY f.family_id
HAVING COUNT(*) = 1;
WHERE 会先筛出 type = 'multiple' 的行,GROUP BY 再按家庭分组。因此,COUNT(*) 统计的是每个 family_id 对应的 multiple 行数,HAVING COUNT(*) = 1 则保留恰好有一行的家庭。
原查询中的 GROUP BY cv.family_id 使用了未定义的别名。根据前面的 FROM familys f,这里应写作 GROUP BY f.family_id。如果“只有一个类型”指该家庭总共只有一条关联记录,且类型为 multiple,这条查询也符合要求。
请求 2:关联行超过一条,且至少一条是 multiple
SELECT f.family_id,
COUNT(*) AS total_count,
SUM(CASE WHEN it.type = 'multiple' THEN 1 ELSE 0 END) AS multiple_count
FROM familys f
JOIN types it
ON it.family_fk = f.family_id
GROUP BY f.family_id
HAVING COUNT(*) > 1
AND SUM(CASE WHEN it.type = 'multiple' THEN 1 ELSE 0 END) > 0;
这里没有在 WHERE 中筛选类型,因此 COUNT(*) 统计该家庭的全部关联行。SUM(CASE ...) 统计其中 type = 'multiple' 的行数。两个 HAVING 条件分别要求总行数大于一,并且至少有一条 multiple 行。
计数口径
以上查询统计关联表中的行。如果 types 中可能有重复记录,而需求是统计不同的类型值或关联对象,需要先确定去重字段,再相应使用 COUNT(DISTINCT ...)。此外,JOIN 会排除没有 types 关联记录的家庭;如果也要显示这类家庭,应改用 LEFT JOIN 并调整筛选条件。
备注:内容仅供参考。
