从大型 mysql 地址数据库中删除重复项
Delete Duplicates from large mysql Address DB
我知道,这里经常讨论从 mysql 中删除重复项。但是 none 的解决方案在我的案例中工作正常。
所以,我有一个地址数据几乎像这样的数据库:
ID; Anrede; Vorname; Nachname; Strasse; Hausnummer; PLZ; Ort; Nummer_Art; Vorwahl; Rufnummer
ID 是主键并且是唯一的。
我有这样的条目:
1;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Mobile;012345;67890
2;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Fixed;045678;877656
电话号码不同不是问题,因为它们与我无关。所以我只想删除姓氏、街道和邮政编码中的重复项。在那种情况下,ID 1 或 ID 2。两者中的哪一个无关紧要。
我用 delete:
试过实际上是这样的
DELETE db
FROM Import_Daten db,
Import_Daten dbl
WHERE db.id > dbl.id AND
db.Lastname = dbl.Lastname AND
db.Strasse = dbl.Strasse AND
db.PLZ = dbl.PLZ;
并插入副本table:
INSERT INTO Import_Daten_1
SELECT MIN(db.id),
db.Anrede,
db.Firstname,
db.Lastname,
db.Branche,
db.Strasse,
db.Hausnummer,
db.Ortsteil,
db.Land,
db.PLZ,
db.Ort,
db.Kontaktart,
db.Vorwahl,
db.Durchwahl
FROM Import_Daten db,
Import_Daten dbl
WHERE db.lastname = dbl.lastname AND
db.Strasse = dbl.Strasse And
db.PLZ = dbl.PLZ;
完整的 table 包含超过 10Mio 行。大小实际上是我的问题。具有 1.5GHZ 和 4GB RAM 的 Macbook 上的 MAMP 服务器上的 mysql 运行s。所以不是很快。 SQL 语句 运行 在 phpmyadmin 中。其实我没有其他系统的可能性。
您可以编写一个 stored procedure,每次 select 一个不同的数据块(例如,在两个值之间 rownumber
)并且仅从该范围内删除。这样你会慢慢一点一点删除你的重复项
您可以添加一个新列,例如uq
并使其成为 UNIQUE
.
ALTER TABLE Import_Daten
ADD COLUMN `uq` BINARY(16) NULL,
ADD UNIQUE INDEX `uq_UNIQUE` (`uq` ASC);
完成后,您可以像这样执行 UPDATE
查询
UPDATE IGNORE Import_Daten
SET
uq = UNHEX(
MD5(
CONCAT(
Import_Daten.Lastname,
Import_Daten.Street,
Import_Daten.Zipcode
)
)
)
WHERE
uq IS NULL;
更新所有条目并再次执行查询后,所有重复项的 uq
字段的值为 NULL
并且可以删除。
那么结果是:
0 row(s) affected, 1 warning(s): 1062 Duplicate entry...
对于新添加的行,始终创建 uq
散列,并在所有条目都是唯一的后考虑将其用作主键。
更有效的两个 table 解决方案如下所示。
我们可以只存储我们真正需要删除的数据和包含重复信息的字段。
假设我们正在寻找 Lastname 、 Branche 和 Haushummer 字段中的重复数据。
创建table来保存重复数据
DROP TABLE data_to_delete;
用我们需要删除的数据填充 table(我假设所有字段都具有 VARCHAR(255) 类型)
CREATE TABLE data_to_delete (
id BIGINT COMMENT 'this field will contain ID of row that we will not delete',
cnt INT,
Lastname VARCHAR(255),
Branche VARCHAR(255),
Hausnummer VARCHAR(255)
) AS SELECT
min(t1.id) AS id,
count(*) AS cnt,
t1.Lastname,
t1.Branche,
t1.Hausnummer
FROM Import_Daten AS t1
GROUP BY t1.Lastname, t1.Branche, t1.Hausnummer
HAVING count(*)>1 ;
现在让我们删除重复数据,所有重复集只保留一条记录
DELETE Import_Daten
FROM Import_Daten LEFT JOIN data_to_delete
ON Import_Daten.Lastname=data_to_delete.Lastname
AND Import_Daten.Branche=data_to_delete.Branche
AND Import_Daten.Hausnummer = data_to_delete.Hausnummer
WHERE Import_Daten.id != data_to_delete.id;
DROP TABLE data_to_delete;
我知道,这里经常讨论从 mysql 中删除重复项。但是 none 的解决方案在我的案例中工作正常。
所以,我有一个地址数据几乎像这样的数据库:
ID; Anrede; Vorname; Nachname; Strasse; Hausnummer; PLZ; Ort; Nummer_Art; Vorwahl; Rufnummer
ID 是主键并且是唯一的。
我有这样的条目:
1;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Mobile;012345;67890
2;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Fixed;045678;877656
电话号码不同不是问题,因为它们与我无关。所以我只想删除姓氏、街道和邮政编码中的重复项。在那种情况下,ID 1 或 ID 2。两者中的哪一个无关紧要。
我用 delete:
试过实际上是这样的DELETE db
FROM Import_Daten db,
Import_Daten dbl
WHERE db.id > dbl.id AND
db.Lastname = dbl.Lastname AND
db.Strasse = dbl.Strasse AND
db.PLZ = dbl.PLZ;
并插入副本table:
INSERT INTO Import_Daten_1
SELECT MIN(db.id),
db.Anrede,
db.Firstname,
db.Lastname,
db.Branche,
db.Strasse,
db.Hausnummer,
db.Ortsteil,
db.Land,
db.PLZ,
db.Ort,
db.Kontaktart,
db.Vorwahl,
db.Durchwahl
FROM Import_Daten db,
Import_Daten dbl
WHERE db.lastname = dbl.lastname AND
db.Strasse = dbl.Strasse And
db.PLZ = dbl.PLZ;
完整的 table 包含超过 10Mio 行。大小实际上是我的问题。具有 1.5GHZ 和 4GB RAM 的 Macbook 上的 MAMP 服务器上的 mysql 运行s。所以不是很快。 SQL 语句 运行 在 phpmyadmin 中。其实我没有其他系统的可能性。
您可以编写一个 stored procedure,每次 select 一个不同的数据块(例如,在两个值之间 rownumber
)并且仅从该范围内删除。这样你会慢慢一点一点删除你的重复项
您可以添加一个新列,例如uq
并使其成为 UNIQUE
.
ALTER TABLE Import_Daten
ADD COLUMN `uq` BINARY(16) NULL,
ADD UNIQUE INDEX `uq_UNIQUE` (`uq` ASC);
完成后,您可以像这样执行 UPDATE
查询
UPDATE IGNORE Import_Daten
SET
uq = UNHEX(
MD5(
CONCAT(
Import_Daten.Lastname,
Import_Daten.Street,
Import_Daten.Zipcode
)
)
)
WHERE
uq IS NULL;
更新所有条目并再次执行查询后,所有重复项的 uq
字段的值为 NULL
并且可以删除。
那么结果是:
0 row(s) affected, 1 warning(s): 1062 Duplicate entry...
对于新添加的行,始终创建 uq
散列,并在所有条目都是唯一的后考虑将其用作主键。
更有效的两个 table 解决方案如下所示。 我们可以只存储我们真正需要删除的数据和包含重复信息的字段。 假设我们正在寻找 Lastname 、 Branche 和 Haushummer 字段中的重复数据。
创建table来保存重复数据
DROP TABLE data_to_delete;
用我们需要删除的数据填充 table(我假设所有字段都具有 VARCHAR(255) 类型)
CREATE TABLE data_to_delete (
id BIGINT COMMENT 'this field will contain ID of row that we will not delete',
cnt INT,
Lastname VARCHAR(255),
Branche VARCHAR(255),
Hausnummer VARCHAR(255)
) AS SELECT
min(t1.id) AS id,
count(*) AS cnt,
t1.Lastname,
t1.Branche,
t1.Hausnummer
FROM Import_Daten AS t1
GROUP BY t1.Lastname, t1.Branche, t1.Hausnummer
HAVING count(*)>1 ;
现在让我们删除重复数据,所有重复集只保留一条记录
DELETE Import_Daten
FROM Import_Daten LEFT JOIN data_to_delete
ON Import_Daten.Lastname=data_to_delete.Lastname
AND Import_Daten.Branche=data_to_delete.Branche
AND Import_Daten.Hausnummer = data_to_delete.Hausnummer
WHERE Import_Daten.id != data_to_delete.id;
DROP TABLE data_to_delete;