如何在MySQL中基于Crime ID查找重复记录(含空值处理)
嘿,我来帮你搞定这个问题!你遇到的核心点是:原来的GROUP BY语句其实能统计空字符串的重复次数,但可能你需要的是要么明确看到空字符串的重复统计,要么把所有重复的具体记录(包括那1万条空字符串的行)都列出来。下面分两种常见场景给你具体方案:
场景1:获取所有重复Crime ID(含空字符串)的出现次数
如果只是想知道每个重复的Crime ID(包括空字符串)到底出现了多少次,其实你原来的语句本身应该能返回空字符串的分组——毕竟那1万条空字符串的记录会被GROUP BY归为一组,COUNT出来的结果就是10000。要是你没看到这个结果,大概率是你的“空”不是标准的空字符串(比如带了空格),那可以先清洗字段再统计:
SELECT TRIM(`Crime ID`) AS cleaned_crime_id, COUNT(*) AS duplicate_count FROM crimedata GROUP BY cleaned_crime_id HAVING duplicate_count > 1;
这个语句会把带空格的空白值统一成空字符串,确保统计准确。要是你的空就是标准的'',那直接用你原来的语句就行,它会包含空字符串的重复组。
场景2:列出所有重复的具体记录(包括空字符串的行)
如果你的需求是要把所有重复的记录(比如每个重复Crime ID对应的每一行数据都列出来),而不是只看聚合后的统计数,那推荐用窗口函数,效率更高:
SELECT * FROM ( SELECT *, COUNT(*) OVER (PARTITION BY `Crime ID`) AS duplicate_count FROM crimedata ) AS temp WHERE duplicate_count > 1;
这个查询会给每一行标记它所属的Crime ID分组的总次数,然后筛选出次数大于1的所有行——那1万条空字符串的记录都会被包含进来,因为它们的duplicate_count是10000,肯定满足条件。
要是你用的是老版本数据库不支持窗口函数,那可以用子查询关联的方式:
SELECT c.* FROM crimedata c JOIN ( SELECT `Crime ID` FROM crimedata GROUP BY `Crime ID` HAVING COUNT(*) > 1 ) AS dup_ids ON c.`Crime ID` = dup_ids.`Crime ID`;
这个逻辑是先找出所有重复的Crime ID(包括空字符串),再关联原表把对应的所有行都拉出来,同样能覆盖空字符串的情况。
小提醒
要是你的“空值”其实是NULL(虽然你说非NULL),那上面的关联条件要调整,因为NULL不能直接用=比较,得改成:
SELECT c.* FROM crimedata c JOIN ( SELECT `Crime ID` FROM crimedata GROUP BY `Crime ID` HAVING COUNT(*) > 1 ) AS dup_ids ON (c.`Crime ID` = dup_ids.`Crime ID` OR (c.`Crime ID` IS NULL AND dup_ids.`Crime ID` IS NULL));
不过你明确说非NULL,所以前面的方案就够用啦。
内容的提问来源于stack exchange,提问作者sebaoka

