根据另一个 table 的内容删除 MySQL 中的重复行
Delete duplicate rows in MySQL based on contents of another table
我有一个 MySQL (5.4) table 有一些行有重复的字段(有时 2-5 个副本),我想删除,只留下一个。但这并不只是选择最高或最低的 id 那么简单。我要删除的重复项是那些在另一个 table.
中没有相应条目的重复项
Table tb_email_to_members
具有 email_id
(自动递增)和 email_address
(以及其他不相关的字段)。例如:
email_id email_address
-------------------------
1 arnold@foo.com
2 foo@foo.com
3 foo@foo.com
4 foo@foo.com
5 jeanluc@foo.com
Table tb_tx
具有 tx_id
(自动递增)和 frn_email_id
(以及其他不相关的字段),其中 tb_tx.frn_email_id
匹配达到 tb_email_to_members.email_id
。例如:
tx_id frn_email_id
--------------------------
100 5
101 2
102 19
103 19
104 19
105 1
我想删除 email_address
在 tb_email_to_members
中重复一次或多次的行,但前提是 tb_tx
中没有包含 frn_email_id
的行email_id
来自 tb_email_to_members
。我需要确保保留一行重复项,即使其中 none 在 tb_tx
中有相应的条目。在上面的示例中,我想从 tb_email_to_members
中删除第 3 行和第 4 行,因为 tb_tx
.
中只存在第 2 行
(本质上,tb_email_to_members
将电子邮件地址映射到另一个 table 中的用户帐户,而 tb_tx
将订单映射到来自 tb_email_to_members
的那些电子邮件地址。)
我可以很容易地找到重复项,并且我看到了很多用于删除重复项的代码,但没有根据另一个 table 的查找失败而只需要删除某些重复项的调整。建议?
这应该可以回答您的问题:
DELETE FROM tb_email_to_members WHERE email_id NOT IN (select frn_email_id FROM tb_tx);
我认为这正是您想要的。它仅删除 tb_email_to_members 中的重复条目,其中 tb_tx 中没有相关行,并保留所有原始条目。
请注意,您没有提及从 tb_tx 中删除条目,因此 table 中的重复项将被单独保留(在您的示例内容中,第 102-104 行)。
我在这里使用的方法基本上是用伪代码实现的:
从 table 的 id_col 中删除 (
SUBQUERY selects 一个 id 列并应用 WHERE 过滤器确保每个 id NOT in (
另一个 SUBQUERY,每个分组中只有 select 的第一项,与第一个 SUBQUERY 非常相似
)
)
那里(第 2 行)还有另一个 SUBQUERY 将整个事情包装起来,这可以防止 MySQL 抱怨你不能 select 从和修改 table同时.
注意:如果您的数据集很大,这可能会很慢。在手动删除大量数据之前备份您的 table!
我知道这是一个相当复杂的查询,但它确实有效。
DELETE FROM tb_email_to_members WHERE email_id IN (
SELECT * FROM (
SELECT ids.eid FROM (
SELECT tb_email_to_members.email_id AS eid, dup.email_id AS eid2, dup.email_address, frn_email_id
FROM tb_email_to_members
LEFT JOIN (
SELECT email_id, email_address FROM tb_email_to_members
GROUP BY email_address
HAVING count(email_id) > 1) AS dup
ON tb_email_to_members.email_address = dup.email_address
INNER JOIN tb_tx tx ON dup.email_id = tx.frn_email_id
) AS ids
WHERE ids.eid NOT IN (
SELECT tb_email_to_members.email_id AS eid FROM tb_email_to_members
LEFT JOIN (
SELECT email_id, email_address FROM tb_email_to_members
GROUP BY email_address
HAVING count(email_id) > 1) AS dup
ON tb_email_to_members.email_address = dup.email_address
INNER JOIN tb_tx tx ON dup.email_id = tx.frn_email_id
GROUP BY dup.email_id
)
) AS foo
)
@MHardwick 和@ShadowRay 几乎做对了。以下内容还检查以确保电子邮件在 tb_email_to_members
中存在 more tan once
DELETE FROM tb_email_to_members
WHERE email_id NOT IN (SELECT frn_email_id FROM tb_tx)
AND email_address IN (SELECT email_address FROM tb_email_to_members GROUP BY email_address HAVING COUNT(email_address) > 1);
显然,将 DELETE
更改为 SELECT *
将向您显示您要删除的内容。
了解 tb
是花絮的缩写?
加分
我有一个 MySQL (5.4) table 有一些行有重复的字段(有时 2-5 个副本),我想删除,只留下一个。但这并不只是选择最高或最低的 id 那么简单。我要删除的重复项是那些在另一个 table.
中没有相应条目的重复项Table tb_email_to_members
具有 email_id
(自动递增)和 email_address
(以及其他不相关的字段)。例如:
email_id email_address
-------------------------
1 arnold@foo.com
2 foo@foo.com
3 foo@foo.com
4 foo@foo.com
5 jeanluc@foo.com
Table tb_tx
具有 tx_id
(自动递增)和 frn_email_id
(以及其他不相关的字段),其中 tb_tx.frn_email_id
匹配达到 tb_email_to_members.email_id
。例如:
tx_id frn_email_id
--------------------------
100 5
101 2
102 19
103 19
104 19
105 1
我想删除 email_address
在 tb_email_to_members
中重复一次或多次的行,但前提是 tb_tx
中没有包含 frn_email_id
的行email_id
来自 tb_email_to_members
。我需要确保保留一行重复项,即使其中 none 在 tb_tx
中有相应的条目。在上面的示例中,我想从 tb_email_to_members
中删除第 3 行和第 4 行,因为 tb_tx
.
(本质上,tb_email_to_members
将电子邮件地址映射到另一个 table 中的用户帐户,而 tb_tx
将订单映射到来自 tb_email_to_members
的那些电子邮件地址。)
我可以很容易地找到重复项,并且我看到了很多用于删除重复项的代码,但没有根据另一个 table 的查找失败而只需要删除某些重复项的调整。建议?
这应该可以回答您的问题:
DELETE FROM tb_email_to_members WHERE email_id NOT IN (select frn_email_id FROM tb_tx);
我认为这正是您想要的。它仅删除 tb_email_to_members 中的重复条目,其中 tb_tx 中没有相关行,并保留所有原始条目。
请注意,您没有提及从 tb_tx 中删除条目,因此 table 中的重复项将被单独保留(在您的示例内容中,第 102-104 行)。
我在这里使用的方法基本上是用伪代码实现的:
从 table 的 id_col 中删除 ( SUBQUERY selects 一个 id 列并应用 WHERE 过滤器确保每个 id NOT in ( 另一个 SUBQUERY,每个分组中只有 select 的第一项,与第一个 SUBQUERY 非常相似 ) )
那里(第 2 行)还有另一个 SUBQUERY 将整个事情包装起来,这可以防止 MySQL 抱怨你不能 select 从和修改 table同时.
注意:如果您的数据集很大,这可能会很慢。在手动删除大量数据之前备份您的 table!
我知道这是一个相当复杂的查询,但它确实有效。
DELETE FROM tb_email_to_members WHERE email_id IN (
SELECT * FROM (
SELECT ids.eid FROM (
SELECT tb_email_to_members.email_id AS eid, dup.email_id AS eid2, dup.email_address, frn_email_id
FROM tb_email_to_members
LEFT JOIN (
SELECT email_id, email_address FROM tb_email_to_members
GROUP BY email_address
HAVING count(email_id) > 1) AS dup
ON tb_email_to_members.email_address = dup.email_address
INNER JOIN tb_tx tx ON dup.email_id = tx.frn_email_id
) AS ids
WHERE ids.eid NOT IN (
SELECT tb_email_to_members.email_id AS eid FROM tb_email_to_members
LEFT JOIN (
SELECT email_id, email_address FROM tb_email_to_members
GROUP BY email_address
HAVING count(email_id) > 1) AS dup
ON tb_email_to_members.email_address = dup.email_address
INNER JOIN tb_tx tx ON dup.email_id = tx.frn_email_id
GROUP BY dup.email_id
)
) AS foo
)
@MHardwick 和@ShadowRay 几乎做对了。以下内容还检查以确保电子邮件在 tb_email_to_members
DELETE FROM tb_email_to_members
WHERE email_id NOT IN (SELECT frn_email_id FROM tb_tx)
AND email_address IN (SELECT email_address FROM tb_email_to_members GROUP BY email_address HAVING COUNT(email_address) > 1);
显然,将 DELETE
更改为 SELECT *
将向您显示您要删除的内容。
了解 tb
是花絮的缩写?