2011-06-24 72 views
20

Tôi có một bảng của các trò chơi, được mô tả như sau:Làm thế nào để xóa các bản sao trong bảng SQL dựa trên nhiều lĩnh vực

+---------------+-------------+------+-----+---------+----------------+ 
| Field   | Type  | Null | Key | Default | Extra   | 
+---------------+-------------+------+-----+---------+----------------+ 
| id   | int(11)  | NO | PRI | NULL | auto_increment | 
| date   | date  | NO |  | NULL |    | 
| time   | time  | NO |  | NULL |    | 
| hometeam_id | int(11)  | NO | MUL | NULL |    | 
| awayteam_id | int(11)  | NO | MUL | NULL |    | 
| locationcity | varchar(30) | NO |  | NULL |    | 
| locationstate | varchar(20) | NO |  | NULL |    | 
+---------------+-------------+------+-----+---------+----------------+ 

Nhưng mỗi trò chơi có một mục trùng lặp trong bảng một nơi nào đó, bởi vì mỗi trò chơi là trong lịch thi đấu cho hai đội. Có một câu lệnh sql tôi có thể sử dụng để xem xét và xóa tất cả các bản sao dựa trên các trường ngày, giờ, hometeam_id, awayteam_id, locationcity và locationstate giống hệt nhau không?

Trả lời

36

Bạn sẽ có thể thực hiện truy vấn con tương quan để xóa dữ liệu. Tìm tất cả các hàng trùng lặp và xóa tất cả các hàng có id nhỏ nhất. Đối với MYSQL, một bên tham gia (chức năng tương đương với EXISTS) cần phải được sử dụng, như vậy:

delete games from games inner join 
    (select min(id) minid, date, time, 
      hometeam_id, awayteam_id, locationcity, locationstate 
    from games 
    group by date, time, hometeam_id, 
       awayteam_id, locationcity, locationstate 
    having count(1) > 1) as duplicates 
    on (duplicates.date = games.date 
    and duplicates.time = games.time 
    and duplicates.hometeam_id = games.hometeam_id 
    and duplicates.awayteam_id = games.awayteam_id 
    and duplicates.locationcity = games.locationcity 
    and duplicates.locationstate = games.locationstate 
    and duplicates.minid <> games.id) 

Để kiểm tra, thay thế delete games from games với select * from games. Không chỉ chạy xóa trên DB của bạn :-)

+0

Tôi đã thử phiên bản được chọn này, và nó trông giống như những gì tôi muốn loại bỏ, nhưng khi tôi thực sự chạy nó với "xóa từ", nó đã ném một lỗi và nói với tôi "Mã lỗi: 1093. Bạn không thể chỉ định bảng mục tiêu 'trò chơi' để cập nhật trong mệnh đề FROM "Bất kỳ ý tưởng nào? – cfrederich

+0

Hãy thử câu trả lời cập nhật, tôi đã thay thế EXISTS bằng INNER JOIN delete. Tôi nghĩ mysql có thể gặp sự cố với mệnh đề xóa và EXISTS. –

2

Miễn là bạn không nhận được id (khóa chính) của bảng trong truy vấn chọn và dữ liệu khác chính xác, bạn có thể sử dụng SELECT DISTINCT để tránh nhận kết quả trùng lặp.

4
select orig.id, 
     dupl.id 
from games orig, 
     games dupl 
where orig.date = dupl.date 
and orig.time = dupl.time 
and orig.hometeam_id = dupl.hometeam_id 
and orig. awayteam_id = dupl.awayeam_id 
and orig.locationcity = dupl.locationcity 
and orig.locationstate = dupl.locationstate 
and orig.id  < dupl.id 

điều này sẽ cung cấp cho bạn các bản sao; bạn có thể sử dụng nó làm truy vấn phụ để chỉ định ID cần xóa.

11

Bạn có thể thử truy vấn như:

DELETE FROM table_name AS t1 
WHERE EXISTS (
SELECT 1 FROM table_name AS t2 
WHERE t2.date = t1.date 
AND t2.time = t1.time 
AND t2.hometeam_id = t1.hometeam_id 
AND t2.awayteam_id = t1.awayteam_id 
AND t2.locationcity = t1.locationcity 
AND t2.id > t1.id) 

này sẽ để lại trong cơ sở dữ liệu chỉ có một ví dụ về mỗi trường hợp trò chơi trong đó có id nhỏ nhất.

+1

cho lỗi cú pháp. –

+0

Giải pháp tuyệt vời! Tuy nhiên, ở dòng cuối cùng, nó phải là '<' để xóa ID nhỏ nhất. – nabroyan

1
DELETE FROM table 
WHERE id = 
    (SELECT t.id 
    FROM table as t 
    JOIN (table as tj ON (t.date = tj.data 
          AND t.hometeam_id = tj.hometeam_id 
          AND t.awayteam_id = tj.awayteam_id 
          ...)) 
+0

Đây là phiên bản rất phức tạp của đơn giản 'xóa khỏi bảng' – piotrpo

+0

oops, bỏ lỡ t.id <> tj.id trong JOIN. – limscoder

2
delete from games 
    where id not in 
    (select max(id) from games 
    group by date, time, hometeam_id, awayteam_id, locationcity, locationstate 
    ); 

Cách giải quyết

select max(id) id from games 
    group by date, time, hometeam_id, awayteam_id, locationcity, locationstate 
into table temp_table; 

delete from games where id in (select id from temp); 
+1

Cách tiếp cận này sẽ chỉ xóa một hàng trùng lặp cho mỗi trò chơi, bất kể có bao nhiêu hàng trùng lặp tồn tại cho trò chơi. –

+0

Điều này mang lại cho tôi cùng một lỗi mà tôi nhận được từ bài đăng của @Neville K. ERROR 1093 (HY000): Bạn không thể chỉ định bảng mục tiêu 'trò chơi' để cập nhật trong mệnh đề FROM – cfrederich

+0

Tôi không thể chỉnh sửa nội dung nào đó được chọn từ trong truy vấn phụ? – cfrederich

5

Để có được danh sách các bản sao entried phù hợp với hai lĩnh vực

select t.ID, t.field1, t.field2 
from (
    select field1, field2 
    from table_name 
    group by field1, field2 
    having count(*) > 1) x, table_name t 
where x.field1 = t.field1 and x.field2 = t.field2 
order by t.field1, t.field2 

Và để xóa tất cả các bản sao chỉ

DELETE x 
FROM table_name x 
JOIN table_name y 
ON y.field1= x.field1 
AND y.field2 = x.field2 
AND y.id < x.id; 
+0

Các truy vấn trên không mong đợi nhưng nó loại bỏ hàng cuối cùng từ resultset. Vì vậy, tôi đã thực hiện một sửa chữa trong truy vấn như sau: DELETE x FROM table_name x THAM GIA table_name y TRÊN y.field1 = x.field1 VÀ y.field2 = x.field2 VÀ y.id> x.id; – Vinayagam

7

Điều tốt nhất làm việc cho tôi là tạo lại bảng.

CREATE TABLE newtable SELECT * FROM oldtable GROUP BY field1,field2; 

Sau đó, bạn có thể đổi tên.

+2

Đây là giải pháp tốt nhất và thẳng tiến hơn. Bạn không thể đi sai bằng cách sử dụng này. – Codex73

+0

Một trong những nhược điểm của việc này là bạn mất các ràng buộc, nhưng bạn chỉ có thể 'TRUNCATE' cũ và sao chép tất cả mọi thứ trở lại vào nó từ newtable, vì vậy nó hoạt động như một quyến rũ – Hissvard

+1

Giải pháp an toàn nhất, tốt hơn nhiều so với một tuyên bố DELETE, IMO. –

Các vấn đề liên quan