如果重复,则从MySQL DB中删除行

时间:2012-03-14 17:53:30

标签: mysql

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

我使用以下查询,但它实际上并不满足我的要求:

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是重复的条目。

我想删除所有这些条目中的所有条目。

有没有办法通过单个查询执行此操作?如果我可以先查看行以确保查询按预期执行,那就太棒了。

提前致谢,

4 个答案:

答案 0 :(得分:4)

试试这个 -

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关于您要删除的行的引用的警告。

答案 1 :(得分:2)

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

然后,也可以使用组中的那些。

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

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

不幸的是,最简单的方法是根据查询分组创建一个临时表,并使用它来加入:

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;

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

答案 2 :(得分:1)

编辑: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

答案 3 :(得分:0)

我还没有测试过,但这样的事情应该可行(这假设你的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
                );