【问题标题】:Deleting rows from MySQL DB if duplicate如果重复,则从 MySQL DB 中删除行
【发布时间】:2012-03-15 09:32:26
【问题描述】:

我正在使用以下查询来显示我的数据库中的重复条目(看起来我不小心运行了两次脚本,尽管它可能更多,因为它可能是恶意用户)。

我正在使用以下查询,尽管它实际上并不能满足我的要求:

SELECT meta_value, COUNT(meta_value) AS cnt
FROM wp_postmeta
GROUP BY meta_value
HAVING cnt > 1
ORDER BY cnt;

我还希望查询检查重复条目是否具有相同的post_idmeta_key

所以,例如:

meta_id     post_id     meta_key    meta_value
1           10          size        large
2           10          colour      blue
3           10          size        large
4           11          size        large

meta_id 1 和 3 是重复条目。

我想删除所有但一个这样的条目。

有没有办法用一个查询来做到这一点?如果我可以先查看行以确保查询按预期执行,那就太好了。

提前致谢,

【问题讨论】:

标签: mysql


【解决方案1】:

试试这个 -

DELETE t2
FROM wp_postmeta t1
INNER JOIN wp_postmeta t2
    ON t1.post_id = t2.post_id
    AND t1.meta_key = t2.meta_key
    AND t1.meta_value = t2.meta_value
    AND t1.meta_id < t2.meta_id

注意@RolandBouman 关于引用您要删除的行的警告。

【讨论】:

  • @RolandBouman - 感谢您更正第二个表别名 :)
  • 漂亮 - 我知道有比我写的更好的方法 - 我当时想不出。完美!
【解决方案2】:

“我还希望查询检查重复条目是否具有相同的 post_id 和 meta_key。”

然后,也使用 group by 中的那些。

SELECT meta_value, COUNT(meta_value) AS cnt
FROM wp_postmeta
GROUP BY post_id, meta_key, meta_value
HAVING cnt > 1
ORDER BY cnt;

“我想删除所有但一个这样的条目。”

不幸的是,这在 MySQL 中并不容易。 (见http://dev.mysql.com/doc/refman/5.5/en/delete.html

有一种称为多表删除语法的东西,但如果您需要加入与要从中删除的表相同的表,它就没有用了。使用子查询也行不通,因为您无法从与要删除的表相同的表中进行选择。

不幸的是,最简单的方法是创建一个基于 group by 查询的临时表并使用它来加入:

CREATE TABLE wp_postmeta_delete
AS
SELECT MIN(meta_id) meta_id
,      post_id 
,      meta_key
,      meta_value
FROM wp_postmeta
GROUP BY post_id, meta_key, meta_value
HAVING count(*) > 1;

DELETE     wp_postmeta.*
FROM       wp_postmeta
INNER JOIN wp_postmeta_delete t2
ON         wp_postmeta.meta_id   != t2.meta_id
AND        wp_postmeta.post_id    = t2.post_id
AND        wp_postmeta.meta_key   = t2.meta_key
AND        wp_postmeta.meta_value = t2.meta_value;

删除行后可以丢弃临时表:

DROP TABLE wp_postmeta_delete;

请注意,在许多情况下,仅删除重复项可能还不够;如果其他表指向重复行,那么您应该迁移这些引用以指向您保留的相应唯一行。

【讨论】:

  • 使用简单的自连接会容易得多。
  • @nncichols 所以向我们展示 sql。请先在 MySQL 中自己尝试一下,因为这是原始帖子的上下文。
  • 我已将其发布在我的答案中。
【解决方案3】:

编辑:nnichols 的答案要好得多。


尝试这样的事情 - 可能有更有效的方法,但我想它似乎有效。

delete from wp_postmeta
where meta_id in 
(select meta_id
from 
     (select meta_key, meta_value, post_id
      from wp_postmeta
      group by meta_key, meta_value, post_id
      having count(*) > 1) problemGroups
inner join wp_postmeta a
      on a.meta_key = problemGroups.meta_key
      and a.meta_value = problemGroups.meta_value
      and a.post_id = problemGroups.post_id) allIDs
and meta_id not in
(select min(meta_id)
from 
     (select meta_key, meta_value, post_id
      from wp_postmeta
      group by meta_key, meta_value, post_id
      having count(*) > 1) problemGroups
inner join wp_postmeta a
      on a.meta_key = problemGroups.meta_key
      and a.meta_value = problemGroups.meta_value
      and a.post_id = problemGroups.post_id
group by problemGroups.meta_key, meta_value, port_id) minIDS

【讨论】:

    【解决方案4】:

    我还没有测试过,但是这样的东西应该可以工作(这假设你的 select 语句抓住了你想要的东西)

    DELETE FROM wp_postmeta
    WHERE meta_id IN (
                    SELECT meta_id
                    FROM wp_postmeta
                    GROUP BY meta_value
                    HAVING COUNT(meta_value) > 1
                    ORDER BY cnt
                    );
    

    【讨论】:

      猜你喜欢
      • 2017-03-30
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 2017-10-11
      • 2013-08-09
      • 2011-07-18
      • 1970-01-01
      相关资源
      最近更新 更多