根据另一个表

时间:2015-08-18 21:17:19

标签: mysql duplicate-removal

我有一个MySQL(5.4)表,其中有一些行有重复的字段(有时2-5个副本),我想删除,只留下一个。但它并不像选择最高或最低ID一样简单。我要删除的重复项是那些在另一个表格中没有相应条目的重复项。

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

表格tb_tx包含tx_id(自动递增)和frn_email_id(以及其他不相关的字段),其中tb_tx.frn_email_id与{tb_email_to_members.email_id匹配1}}。例如:

tx_id         frn_email_id
--------------------------
100           5
101           2
102           19
103           19
104           19
105           1

我希望在email_address中删除tb_email_to_members重复一次或多次的行,但仅限于frn_email_idtb_tx中没有包含email_id的行的tb_email_to_members 1}}来自tb_tx。我需要确保留下一行重复项,即使它们都没有tb_email_to_members中的相应条目。在上面的示例中,我想从tb_tx中删除第3行和第4行,因为tb_email_to_members中只存在第2行。

(实质上,tb_tx将电子邮件地址映射到另一个表中的用户帐户,tb_email_to_members将订单映射到tabLayout.setSelectedTabIndicatorColor(Color.parseColor("#FFFFFF")); 的电子邮件地址。)

我可以很容易地找到重复项,并且我看到很多用于删除重复项的代码,但没有根据需要根据另一个表的查找失败而仅删除某些重复项的调整。建议?

3 个答案:

答案 0 :(得分:0)

这应该回答你的问题:

DELETE FROM tb_email_to_members WHERE email_id NOT IN (select frn_email_id FROM tb_tx);

答案 1 :(得分:0)

我认为,这正是你想要的。它仅删除tb_email_to_members中的重复条目,其中tb_tx中没有相关行,并保留所有原始文件。

请注意,您没有说明如何从tb_tx中删除条目,因此该表中的重复项将保持不变(在示例内容中,行102-104)。

我在这里使用的方法基本上是伪代码:

DELETE FROM表WHERE id_col IN(  SUBQUERY选择一个id列并应用WHERE过滤器,确保每个id NOT in(   另一个SUBQUERY只选择每个分组中的第一个项目,与第一个SUBQUERY非常相似   ) )

那里有另一个SUBQUERY(第2行)包装整个事物,这可以防止MySQL抱怨你不能同时选择和修改表。

注意:如果您的数据集很大,这可能会很慢。在手动删除大量数据之前备份表格!

我意识到这是一个相当复杂的查询,但确实有效。

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
)

答案 2 :(得分:0)

@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的加分点是花絮的简称?