Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 使用自定义逻辑删除重复行_Mysql_Duplicates - Fatal编程技术网

Mysql 使用自定义逻辑删除重复行

Mysql 使用自定义逻辑删除重复行,mysql,duplicates,Mysql,Duplicates,我一直在寻找一种方法,使用一些自定义逻辑删除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 我尝试了这个查询,但没有成功(如果

我一直在寻找一种方法,使用一些自定义逻辑删除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示例中所示):

删除t
从表t到表t2
t.id!=t2.id

和t.population您可以使用子查询进行连接,该子查询返回每个城市人口最多的行的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。您可以使用子查询进行连接,该子查询返回每个城市人口最多的行的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
我需要额外的子查询嵌套级别,因为一个名称有多个具有相同填充的行。因此,它首先需要获得每个名称的最大人口,然后在该组中选择一个特定的ID,该ID的
max(ID)

看起来像是要在
名称
列中“匹配”城市

在将SELECT语句转换为DELETE语句之前,先编写并测试SELECT语句

SELECT d.*
  FROM table d
  JOIN table k
    ON k.name        = d.name 
   AND k.population  > d.population 
   AND k.id         <> d.id
内联视图
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语句。

看起来您希望在
名称
列中对城市进行“匹配”

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;
在将SELECT语句转换为DELETE语句之前,先编写并测试SELECT语句

SELECT d.*
  FROM table d
  JOIN table k
    ON k.name        = d.name 
   AND k.population  > d.population 
   AND k.id         <> d.id
内联视图
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语句

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;
一旦你检查了数据

DROP TABLE archive_table;


如果有多个同名且人口最多,则需要保留全部或仅保留一行?在这种情况下,我只想保留一行(不考虑所选行)如果有多个同名且人口最多,则需要保留全部或仅保留一行?在这种情况下,我只想保留一行(不考虑所选行)关于“不同的方法”,请参阅我的答案。@spencer7593:非常感谢您的帮助。然而,我专注于Barmar解决方案,它只是起了作用;-)关于“不同的方法”,请参阅我的答案。@spencer7593:非常感谢您的帮助。然而,我专注于Barmar解决方案,它只是起了作用;-)如果有外键指向此表的其他表,则ID将随之更改。虽然
DELETE
方法也可能有问题,因为删除相关行时它们将变得无效。如果Guillame的数据库中有数百万行,那么就地删除会导致锁定问题。但我怀疑两者都不适用。这是geonames数据库,因此可能有数百万行。是的,如果有外键指向此表的其他表,则ID将因此改变。虽然
DELETE
方法也可能有问题,因为删除相关行时它们将变得无效。如果Guillame的数据库中有数百万行,那么就地删除会导致锁定问题。但我怀疑两者都不适用。这是geonames数据库,所以可能有数百万行。我刚刚尝试了你的解决方案,它删除了所有行;p@GuillaumeSTLRspencer7593是正确的,我修复了查询。@spencer7593正确。另一种方法是使用
WHERE id NOT IN(返回所有maxid的子查询)
@Barmar:或者我们可以使用反连接。删除所有行,除了那些id与要保留的id值列表中的行匹配的行。是的,这是我通常使用的模式。但这个查询已经够复杂了。:)我刚刚尝试了你的解决方案,它已经删除了所有的行;p@GuillaumeSTLRspencer7593是正确的,我修复了查询。@spencer7593正确。另一种方法是使用
WHERE id NOT IN(返回所有maxid的子查询)
@Barmar:或者我们可以使用反连接。删除所有行,除了那些id与要保留的id值列表中的行匹配的行。是的,这是我通常使用的模式。但这个查询已经够复杂了。:)