Jak usunąć z Select w MySQL?


86

Ten kod nie działa z MySQL 5.0, jak go ponownie napisać, aby działał

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

Chcę usunąć kolumny, które nie mają unikalnego identyfikatora. Dodam, że przeważnie jest to jedyny identyfikator (próbowałem w składni i też nie działa).

Odpowiedzi:


213

SELECTZapytania (sub) zwracają zestawy wyników . Więc musisz użyć IN, a nie =w swojej WHEREklauzuli.

Ponadto, jak pokazano w tej odpowiedzi , nie można modyfikować tej samej tabeli z podzapytania w ramach tego samego zapytania. Jednakże, można albo SELECTnastępnie DELETEw oddzielnych zapytań lub gniazda innego podzapytania i alias wynikiem wewnętrzny podzapytania (patrzy raczej hacky, choć):

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

Lub użyj złączeń zgodnie z sugestią Mchl .


1
Miałem stolik ze 150 zduplikowanymi kluczami. Wykonałem powyższe zapytanie i powiedziało, że "dotyczy 144 wierszy", ale wciąż są zduplikowane klucze. Więc ponownie wykonałem zapytanie i mówi, że dotyczy to 5 wierszy, znowu: dotyczy to 1 wiersza. Potem zniknęły wszystkie zduplikowane klucze. Dlaczego to?
Alex

Dzieje się tak, ponieważ usuwasz tylko 1 wpis z każdego zestawu duplikatów:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

# 1248 - Każdy pochodzi tabela musi mieć swój własny alias
thang

@thang: Dlatego właśnie powiedziałem, aby aliasować wewnętrzne podzapytanie.
BoltClock

1
Czy możesz wyjaśnić, co robi „As p”?
Cricketer

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

Wydaje się, że to działa, ale jestem zdezorientowany składnią i nie mogę znaleźć żadnych innych zasobów, aby to wyjaśnić. CROSS JOINnajwyraźniej wykonuje sprzężenie kartezjańskie, więc wygląda na to, że może to wykonać niepotrzebną pracę lub działać nieoptymalnie? Czy ktoś mógłby to wyjaśnić?
wintron

Zrobi produkt kartezjański tylko wtedy, gdy nie ma USINGklauzuli. Z USINGiloczynem ogranicza się do par o tej samej wartości w idkolumnie, więc w rzeczywistości jest bardzo ograniczony.
Mchl

Czy mógłbyś zrobić to samo ze złączeniem wewnętrznym? 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: Tak. Funkcjonalnie te łączenia są dokładnie takie same.
Mchl

5

możesz użyć sprzężenia wewnętrznego:

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

Jeśli chcesz usunąć wszystkie duplikaty, ale po jednym z każdego zestawu duplikatów, oto jedno rozwiązanie:

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;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.