Bagaimana cara menghapus dari pilih di MySQL?

87

Kode ini tidak berfungsi untuk MySQL 5.0, bagaimana cara menulis ulang untuk membuatnya berfungsi

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

Saya ingin menghapus kolom yang tidak memiliki id unik. Saya akan menambahkan bahwa sebagian besar waktu itu hanya satu id (saya mencoba sintaks in dan itu tidak berfungsi dengan baik).

IAdapter
sumber

Jawaban:

217

SELECT(sub) kueri mengembalikan kumpulan hasil . Jadi, Anda perlu menggunakan IN, bukan =di WHEREklausa Anda .

Selain itu, seperti yang diperlihatkan dalam jawaban ini, Anda tidak dapat mengubah tabel yang sama dari subkueri dalam kueri yang sama. Namun, Anda SELECTkemudian dapat DELETEdalam kueri terpisah, atau menyarangkan subkueri lain dan alias hasil subkueri bagian dalam (meskipun tampak agak hacky):

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

Atau gunakan gabungan seperti yang disarankan oleh Mchl .

BoltClock
sumber
1
Saya punya meja dengan 150 kunci duplikat. Saya mengeksekusi kueri di atas dan dikatakan "144 baris terpengaruh", tetapi masih ada kunci duplikat. Jadi saya mengeksekusi kueri lagi dan dikatakan 5 baris terpengaruh, sekali lagi: 1 baris terpengaruh. Kemudian semua kunci duplikat pergi. Kenapa ini?
Alex
Ini terjadi, karena Anda hanya menghapus 1 entri dari setiap kumpulan duplikat:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg
# 1248 - Setiap tabel turunan harus memiliki alias sendiri
thang
@thang: Itulah mengapa saya mengatakan untuk alias subkueri bagian dalam.
BoltClock
1
Bisakah Anda menjelaskan apa yang dilakukan "As p"?
Pemain 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)
Mchl
sumber
Ini tampaknya berfungsi, tetapi saya bingung dengan sintaksnya dan tidak dapat menemukan sumber daya apa pun untuk menjelaskannya. CROSS JOINtampaknya melakukan gabungan kartesian, jadi sepertinya ini mungkin melakukan pekerjaan yang tidak perlu, atau bekerja secara sub-optimal? Adakah yang bisa menjelaskan?
musim dingin
Ini akan melakukan produk kartesian hanya jika tidak ada USINGklausul. Dengan USINGperkalian terbatas pada pasangan yang memiliki nilai yang sama pada idkolom, sehingga sangat terbatas.
Mchl
Bisakah Anda melakukan hal yang sama dengan inner join? 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: Ya. Secara fungsional, gabungan ini persis sama.
Mchl
6

Anda dapat menggunakan gabungan dalam:

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  
Charif DZ
sumber
0

Jika Anda ingin menghapus semua duplikat, tetapi satu dari setiap kumpulan duplikat, ini adalah salah satu solusinya:

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;
havvg
sumber