Cách tìm trùng lặp trong 2 cột không phải 1


107

Tôi có một bảng cơ sở dữ liệu MySQL với hai cột mà tôi quan tâm. Cá nhân chúng có thể có bản sao, nhưng chúng không bao giờ được có bản sao của CẢ HAI trong số chúng có cùng giá trị.

stone_idcó thể có bản sao miễn là mỗi upshargetiêu đề là khác nhau và ngược lại. Nhưng giả sử stone_id= 412 và upcharge_title= "sapphire", sự kết hợp đó chỉ nên xảy ra một lần.

Điều này là ổn:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "ruby"

Điều này KHÔNG ổn:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "sapphire"

Có một truy vấn sẽ tìm thấy các bản sao trong cả hai trường không? Và nếu có thể có cách nào để đặt cơ sở dữ liệu của tôi không cho phép điều đó không?

Tôi đang sử dụng MySQL phiên bản 4.1.22

Câu trả lời:


192

Bạn nên thiết lập một khóa tổng hợp giữa hai trường. Điều này sẽ yêu cầu một stone_id và upcharge_title duy nhất cho mỗi hàng.

Đối với việc tìm thấy các bản sao hiện có, hãy thử điều này:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1

Cảm ơn bạn, điều đó chọn họ. Bạn có thể tốt bụng cho tôi biết làm thế nào để xóa các bản sao (nhưng để lại 1 bản sao) XIN CẢM ƠN !!
JD Isaacks

2
Một cách là lấy tất cả các dữ liệu riêng biệt và tạo lại bảng.
Miyagi Coder

1
@John Isaacks: Nếu không có trường nào khác mà bạn có thể phân biệt chúng (tức là tất cả các trường đều trùng lặp), thì bạn sẽ phải xóa cả hai hàng và tạo lại một. Một cách sẽ là sao chép các bản sao vào một bản sao của bảng, xóa chúng khỏi bản gốc và chèn lại các hàng khác biệt với bản sao.
P Daddy

Điều này không hoạt động trên postgres 8.1, ai đó có thể giúp tôi một tay không?
Lennon

cảm ơn rất nhiều, thứ tự mà bạn nhóm theo vấn đề?
Andrew

35

Tôi thấy hữu ích khi thêm chỉ mục unqiue bằng cách sử dụng "ALTER IGNORE" để loại bỏ các bản sao và thực thi các bản ghi duy nhất mà bạn muốn làm. Vì vậy, cú pháp sẽ là:

ALTER IGNORE TABLE `table` ADD UNIQUE INDEX(`id`, `another_id`, `one_more_id`);

Điều này có hiệu quả bổ sung ràng buộc duy nhất có nghĩa là bạn sẽ không bao giờ có các bản ghi trùng lặp và việc BỎ QUA sẽ xóa các bản sao hiện có.

Bạn có thể đọc thêm về eh ALTER IGNORE tại đây: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

Cập nhật: Tôi đã được @Inquisitive thông báo rằng điều này có thể không thành công trong các phiên bản MySql> 5.5:

Nó không thành công trên MySQL> 5.5 và trên bảng InnoDB và trong Percona vì tính năng tạo chỉ mục nhanh InnoDB của họ [ http://bugs.mysql.com/bug.php?id=40344] . Trong trường hợp này trước tiên hãy chạy set session old_alter_table=1và sau đó lệnh trên sẽ hoạt động tốt

Cập nhật - ALTER IGNORELoại bỏ trong 5.7

Từ các tài liệu

Kể từ MySQL 5.6.17, mệnh đề BỎ QUA không được dùng nữa và việc sử dụng nó tạo ra cảnh báo. IGNORE bị loại bỏ trong MySQL 5.7.

Một trong những nhà phát triển MySQL đưa ra hai lựa chọn thay thế :

  • Nhóm theo các trường duy nhất và xóa như đã thấy ở trên
  • Tạo một bảng mới, thêm một chỉ mục duy nhất, sử dụng INSERT IGNORE, ví dụ:
CREATE TABLE duplicate_row_table LIKE regular_row_table;
ALTER TABLE duplicate_row_table ADD UNIQUE INDEX (id, another_id);
INSERT IGNORE INTO duplicate_row_table SELECT * FROM regular_row_table;
DROP TABLE regular_row_table;
RENAME TABLE duplicate_row_table TO regular_row_table;

Nhưng tùy thuộc vào kích thước bàn của bạn, điều này có thể không thực tế


1
Đúng, nhưng ít nhất để lần sau bạn biết. Tôi đã cùng một vấn đề và nghĩ rằng nó tốt để chia sẻ với những người khác
SeanDowney

Tôi chỉ trêu là nó đã muộn 3 năm. Thực sự rất vui vì bạn đã chia sẻ. Do đó cộng 1.
JD Isaacks

Tôi tưởng tượng điều này sẽ loại bỏ một trong các bản sao một cách tùy ý để đảm bảo không có dữ liệu khác nhau giữa mỗi hàng có thể hữu ích để biết hoặc lưu giữ.
Joshua Pinter,

+1 cho câu trả lời dù đã trễ 2 năm. Tôi đã vô tình xóa một khóa tổng hợp và đây là một phần mềm cứu mạng. Cảm ơn bạn
ivcode

Tôi đã thử một vài kỹ thuật tìm trùng lặp và không có kỹ thuật nào đơn giản và nhanh chóng. Cảm ơn bạn đã chia sẻ phương pháp này.
Kristjan O.

8

Bạn có thể tìm thấy các bản sao như thế này ..

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1

4

Để tìm các bản sao:

select stone_id, upcharge_title from tablename group by stone_id, upcharge_title having count(*)>1

Để hạn chế tránh điều này trong tương lai, hãy tạo một khóa duy nhất tổng hợp trên hai trường này.


1
Cảm ơn bạn rất nhiều, bạn có thể vui lòng cho tôi biết làm thế nào để xóa tất cả trừ một trong những bản sao. Và làm cách nào để thiết lập khóa compisite trong phpmyadmin. CẢM ƠN BẠN!!!
JD Isaacks

3

Ngẫu nhiên, một ràng buộc duy nhất tổng hợp trên bảng sẽ ngăn điều này xảy ra ngay từ đầu.

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(Đây là T-SQL hợp lệ. Không chắc chắn về MySQL.)


1
Tôi nghĩ rằng điều đó hiệu quả nhưng nó sẽ không cho phép tôi làm điều đó cho đến khi tôi xóa các bản sao trước. Cảm ơn.
JD Isaacks

1

bài đăng SO này đã giúp tôi, nhưng tôi cũng muốn biết cách xóa và giữ một trong các hàng ... đây là một giải pháp PHP để xóa các hàng trùng lặp và giữ một hàng (trong trường hợp của tôi chỉ có 2 cột và nó nằm trong một chức năng để xóa các liên kết danh mục trùng lặp)

$dupes = $db->query('select *, count(*) as NUM_DUPES from PRODUCT_CATEGORY_PRODUCT group by fkPRODUCT_CATEGORY_ID, fkPRODUCT_ID having count(*) > 1');
if (!is_array($dupes))
    return true;
foreach ($dupes as $dupe) {
    $db->query('delete from PRODUCT_CATEGORY_PRODUCT where fkPRODUCT_ID = ' . $dupe['fkPRODUCT_ID'] . ' and fkPRODUCT_CATEGORY_ID = ' . $dupe['fkPRODUCT_CATEGORY_ID'] . ' limit ' . ($dupe['NUM_DUPES'] - 1);
}

(giới hạn NUM_DUPES - 1) là những gì giữ nguyên một hàng ...

cảm ơn tất cả


3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)sẽ loại bỏ các hàng trùng lặp chỉ để lại một cặp duy nhất.
dev-null-dweller,
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.