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.