Como excluir da seleção no MySQL?


86

Este código não funciona para MySQL 5.0, como reescrevê-lo para que funcione

DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id  HAVING ( COUNT(id) > 1 ))

Eu quero excluir colunas que não têm id exclusivo. Vou acrescentar que na maioria das vezes é apenas um id (tentei a sintaxe in e não funciona bem).

Respostas:


213

SELECT(sub) consultas retornam conjuntos de resultados . Portanto, você precisa usar IN, não =em sua WHEREcláusula.

Além disso, conforme mostrado nesta resposta, você não pode modificar a mesma tabela de uma subconsulta dentro da mesma consulta. No entanto, você pode SELECT, em seguida, DELETEem consultas separadas, ou ninho outra subconsulta e alias o resultado da subconsulta interna (aparência bastante hacky, embora):

DELETE FROM posts WHERE id IN (
    SELECT * FROM (
        SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
    ) AS p
)

Ou use junções conforme sugerido por Mchl .


1
Eu tinha uma mesa com 150 chaves duplicadas. Eu executei a consulta acima e ela disse "144 linhas afetadas", mas ainda havia chaves duplicadas. Então eu executei a consulta novamente e ela diz 5 linhas afetadas, novamente: 1 linha afetada. Então, todas as chaves duplicadas foram embora. Por que é isso?
Alex

Isso está acontecendo porque você está excluindo apenas 1 entrada de cada conjunto de duplicatas:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

# 1248 - Cada derivado tabela deve ter o seu próprio apelido
thang

@thang: É por isso que eu disse para criar um alias para a subconsulta interna.
BoltClock

1
Você poderia explicar o que o "As p" faz?
Jogador de críquete de

22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)

Isso parece funcionar, mas estou confuso com a sintaxe e não consigo encontrar nenhum recurso em outro lugar para explicá-lo. CROSS JOINaparentemente executa uma junção cartesiana, então parece que isso pode fazer um trabalho desnecessário ou ter um desempenho abaixo do ideal? Alguém poderia explicar?
wintron

Só fará um produto cartesiano se não houver USINGcláusula. Com USINGo produto é limitado a pares de mesmo valor na idcoluna, por isso é na verdade muito limitado.
Mchl

Você poderia fazer a mesma coisa com a junção interna? IEDELETE p1 FROM posts AS p1 INNER JOIN ( SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1 ) AS p2 ON p2.ID=p1.ID
Kodos Johnson

1
@Andrew: Sim. Funcionalmente, essas junções são exatamente as mesmas.
Mchl de

5

você pode usar junção interna:

DELETE 
    ps 
FROM 
    posts ps INNER JOIN 
         (SELECT 
           distinct id 
         FROM 
             posts 
         GROUP BY id  
      HAVING COUNT(id) > 1 ) dubids on dubids.id = ps.id  

0

Se você deseja excluir todas as duplicatas, exceto uma de cada conjunto de duplicatas, esta é uma solução:

DELETE posts
FROM posts
LEFT JOIN (
    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) = 1

    UNION

    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) != 1
) AS duplicate USING (id)
WHERE duplicate.id IS NULL;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.