Làm cách nào để xóa khỏi vùng chọn trong MySQL?


86

Mã này không hoạt động cho MySQL 5.0, làm thế nào để viết lại nó để làm cho nó hoạt động

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

Tôi muốn xóa các cột không có id duy nhất. Tôi sẽ thêm rằng hầu hết thời gian là một id duy nhất của nó (tôi đã thử cú pháp trong và nó cũng không hoạt động).

Câu trả lời:


212

SELECT(phụ) truy vấn trả về tập kết quả . Vì vậy, bạn cần sử dụng IN, không phải =trong WHEREmệnh đề của bạn .

Ngoài ra, như được hiển thị trong câu trả lời này, bạn không thể sửa đổi cùng một bảng từ một truy vấn con trong cùng một truy vấn. Tuy nhiên, bạn có thể SELECTsau đó DELETEtrong các truy vấn riêng biệt hoặc lồng một truy vấn con khác và đặt bí danh là kết quả truy vấn con bên trong (mặc dù trông khá khó hiểu):

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

Hoặc sử dụng các phép nối theo gợi ý của Mchl .


1
Tôi đã có một bảng với 150 khóa trùng lặp. Tôi đã thực hiện truy vấn ở trên và nó cho biết "144 hàng bị ảnh hưởng", nhưng vẫn có các khóa trùng lặp. Vì vậy, tôi thực hiện lại truy vấn và nó cho biết 5 hàng bị ảnh hưởng, một lần nữa: 1 hàng bị ảnh hưởng. Sau đó, tất cả các khóa trùng lặp đã biến mất. Tại sao thế này?
Alex

Đây là xảy ra, bởi vì bạn chỉ xóa 1 entry ra của mỗi bộ bản sao:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

# 1248 - Mỗi bảng dẫn xuất phải có bí danh riêng
thang

@thang: Đó là lý do tại sao tôi nói với bí danh là truy vấn con bên trong.
BoltClock

1
Bạn vui lòng giải thích "As p" làm gì?
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)

Điều này có vẻ hoạt động, nhưng tôi bối rối bởi cú pháp và không thể tìm thấy bất kỳ tài nguyên nào ở nơi khác để giải thích nó. CROSS JOINdường như thực hiện một phép nối cacte, vì vậy, có vẻ như điều này có thể làm công việc không cần thiết hoặc thực hiện không tối ưu? Bất cứ ai có thể giải thích?
wintron

Nó sẽ chỉ làm một sản phẩm cacte nếu không có USINGđiều khoản nào . Với USINGsản phẩm chỉ giới hạn cho các cặp có cùng giá trị trong idcột nên thực tế rất hạn chế.
Mchl

Bạn có thể làm điều tương tự với tham gia bên trong không? 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: Vâng. Về mặt chức năng các phép nối này hoàn toàn giống nhau.
Mchl

5

bạn có thể sử dụng kết nối bên trong:

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

Nếu bạn muốn xóa tất cả các bản sao, nhưng một trong số mỗi tập hợp các bản sao, đây là một giải pháp:

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.