MySQL'de seçimden nasıl silinir?


87

Bu kod MySQL 5.0 için çalışmıyor, çalışması için nasıl yeniden yazılır

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

Benzersiz kimliği olmayan sütunları silmek istiyorum. Çoğu zaman onun tek kimliği olduğunu ekleyeceğim (sözdizimini denedim ve o da çalışmıyor)

Yanıtlar:


217

SELECT(alt) sorgular sonuç kümelerini döndürür . Yani , kendi maddenizde INdeğil =, kullanmanız gerekir WHERE.

Ek olarak, bu yanıtta gösterildiği gibi , aynı tabloyu aynı sorgu içindeki bir alt sorudan değiştiremezsiniz. Ancak, SELECTdaha sonra DELETEayrı sorgularda ya da başka bir alt sorguyu iç içe yerleştirebilir ve iç alt sorgu sonucunu takma ad verebilirsiniz (yine de oldukça karmaşık görünüyor):

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

Veya Mchl tarafından önerildiği gibi birleşimleri kullanın .


1
150 yinelenen anahtarı olan bir masam vardı. Yukarıdaki sorguyu çalıştırdım ve "144 satır etkilendi" dedi, ancak orada hala yinelenen anahtarlar var. Bu yüzden sorguyu tekrar çalıştırdım ve 5 satırın etkilendiğini söylüyor: 1 satır etkilendi. Sonra tüm yinelenen anahtarlar gitti. Bu neden?
Alex

Bu gerçekleşiyor, çünkü her kopya grubundan yalnızca 1 girişi siliyorsunuz:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

# 1248 - Her türetilmiş tablonun kendi takma adı olmalıdır
thang

@thang: Bu yüzden iç alt sorguyu takma adla adlandırmamı söyledim.
BoltClock

1
Lütfen "As p" nin ne yaptığını açıklar mısınız?
Kriket

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

Bu işe yarıyor gibi görünüyor, ancak sözdizimi kafam karıştı ve bunu açıklayacak başka bir kaynak bulamıyorum. CROSS JOINgörünüşe göre kartezyen birleştirme gerçekleştiriyor, bu yüzden bu gereksiz işler yapabilir veya yetersiz performans gösterebilir. Biri açıklayabilir mi?
wintron

Kartezyen bir ürün ancak hiçbir USINGmadde yoksa yapacaktır . İle USINGürünü aynı değere sahip olan çift sınırlıdır idsütun, bu nedenle, aslında çok sınırlı.
Mchl

İç birleştirme ile aynı şeyi yapabilir misin? 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: Evet. İşlevsel olarak bu birleşimler tamamen aynıdır.
Mchl

6

iç birleştirmeyi kullanabilirsiniz:

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

Tüm kopyaları, ancak her kopya kümesinden birini silmek istiyorsanız, bu bir çözümdür:

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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.