我很难找到一种方法来使用一些自定义逻辑删除MySQL数据库中的一些重复行。
实际数据:
id name population
1 CityA 1000
2 CityA 50
3 CityA 0
4 CityB 0
5 CityB 0
6 CityC 10
期望的结果:
id name population
1 CityA 1000
4 CityB 0
6 CityC 10
我尝试了这个查询但没有成功(如果所有人口都等于0
,它已删除了城市的所有行,就像在CityB示例中一样):
DELETE t
FROM table AS t, table AS t2
WHERE t.id != t2.id
AND t.population <= t2.population
任何超级英雄都可以解决这个超级问题吗?
[编辑]工作解决方案:http://sqlfiddle.com/#!9/ea3e3/2
答案 0 :(得分:2)
您可以使用子查询进行联接,该子查询返回每个城市人口最多的行的ID。
DELETE t1
FROM YourTable AS t1
JOIN (SELECT name, MAX(id) AS maxid
FROM YourTable AS t2
JOIN (SELECT name, MAX(population) AS maxpop
FROM YourTable
GROUP BY name) AS t3
ON t2.name = t3.name AND t2.population = t3.maxpop
GROUP BY t2.name) AS t4
ON t1.name = t4.name AND t1.id != t4.maxid
我需要额外级别的子查询嵌套,因为您有多个行具有相同的名称。因此,首先需要获取每个名称的最大总数,然后使用MAX(id)
选择该组中的特定ID。
答案 1 :(得分:1)
看起来你想&#34;匹配&#34;在name
列中的城市。
首先编写一个SELECT语句,然后在将其转换为DELETE语句之前对其进行测试。
SELECT d.*
FROM table d
JOIN table k
ON k.name = d.name
AND k.population > d.population
AND k.id <> d.id
我们希望保留k
中的行,并从d
中删除该行。
将SELECT关键字替换为DELETE。将其转换为DELETE语句。
请注意,如果有多个行具有相同的&#34;最高&#34;一个城市的人口,这个查询不会识别那些。摆脱&#34;重复&#34;在人口价值相同的情况下,我们需要采用略有不同的方法。
我使用反加入:
SELECT d.*
FROM table d
LEFT
JOIN ( SELECT MIN(r.id) AS min_id
FROM ( SELECT t.name
, MAX(t.population) AS max_pop
FROM table t
GROUP BY t.name
) s
JOIN table r
ON r.name = s.name
AND r.population = s.max_pop
GROUP BY r.name
) q
ON q.min_id = d.id
WHERE q.min_id IS NULL
内联视图q
应从我们要保留的行返回id
值列表。在该列表中没有id
的任何行都是我们要删除的行。
如果MySQL在内联视图中对表引用进行了讨论,我们可以将其作为一种解决方法包装在另一个内联视图中。
SELECT d.*
FROM table d
LEFT
JOIN ( SELECT q.min_id
FROM ( SELECT MIN(r.id) AS min_id
FROM ( SELECT t.name
, MAX(t.population) AS max_pop
FROM table t
GROUP BY t.name
) s
JOIN table r
ON r.name = s.name
AND r.population = s.max_pop
GROUP BY r.name
) q
) p
ON p.min_id = d.id
WHERE p.min_id IS NULL
将最外面的SELECT关键字替换为DELETE关键字,将其转换为DELETE语句。
答案 2 :(得分:0)
CREATE TABLE new_table (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30),
population INT
);
INSERT INTO new_table (name, population)
SELECT old.name, MAX(old.population)
FROM current_table old
GROUP BY old.name;
RENAME TABLE current_table TO archive_table
, new_table TO current_table;
然后,一旦您检查了数据
DROP TABLE archive_table;