MySQL에서 중복 행 제거


375

다음 필드가있는 테이블이 있습니다.

id (Unique)
url (Unique)
title
company
site_id

이제 같은 행을 제거해야합니다 title, company and site_id. 이를 수행하는 한 가지 방법은 스크립트 ( PHP) 와 함께 다음 SQL을 사용하는 것입니다 .

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

이 쿼리를 실행 한 후 서버 측 스크립트를 사용하여 중복을 제거 할 수 있습니다.

그러나 이것이 SQL 쿼리를 통해서만 수행 할 수 있는지 알고 싶습니다.


1
빠른 질문 : 항상 중복 (제목, 회사, site_id)을 원하지 않습니까? 그렇다면 제목, 회사 및 site_id가 고유하도록 데이터베이스에 제약 조건을 설정했습니다. 따라서 정리 프로세스가 필요하지 않습니다. 그리고 한 줄의 SQL 만 필요합니다.
J. Polfer

1
이 stackoverflow 링크를 참조하십시오 . 매력적으로 저에게 효과적이었습니다.

:이 솔루션 (다른 스레드에 게시) 추천 할 수 stackoverflow.com/a/4685232/195835
사이먼 동쪽

답변:


607

이렇게하는 가장 쉬운 방법 UNIQUE은 3 개의 열에 인덱스 를 추가하는 것 입니다. ALTER문장 을 작성할 때 IGNORE키워드를 포함 시키십시오 . 이렇게 :

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

모든 중복 행이 삭제됩니다. 추가 혜택으로, INSERTs중복되는 미래 는 오류가 발생합니다. 항상 그렇듯이 이와 같은 것을 실행하기 전에 백업을 원할 수도 있습니다 ...


8
재미있는 그 중복을 제거하기 위해 절 차종을 무시하지만, 가정의 요구를 일치하지 않을 수 있습니다 관심사입니다. 가장 잘 맞는 가장 일치하는 사운드에 맞지 않는 값이 잘려 있습니까?
OMG Ponies

75
InnoDB를 사용하는 경우 레코드에 문제가있을 수 있으므로 InnoDB 데이터베이스와 함께 ALTER IGNORE TABLE을 사용하는 것과 관련된 알려진 버그가 있습니다.
DarkMantis

27
앞에서 언급 한 @DarkMantis 버그해결책 입니다.
Jordan Arseno

42
InnoDB 테이블의 경우 먼저 다음 쿼리를 실행하십시오.set session old_alter_table=1;
shock_one

51
이는 5.7.4에서 더 이상 지원하지 않습니다 dev.mysql.com/doc/refman/5.7/en/alter-table.html
레이 박스터

180

열 속성을 변경하지 않으려면 아래 쿼리를 사용하십시오.

고유 ID가있는 열 (예 : auto_increment열)이 있으므로이를 사용하여 중복을 제거 할 수 있습니다.

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

MySQL에서는 NULL 안전 등호 연산자 (일명 "우주선 연산자" )를 사용하여 훨씬 단순화 할 수 있습니다 .

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;

3
이 솔루션이 제대로 작동하지 않습니다. 복제 레코드를 만들려고 시도했지만 (20 행 영향)과 같은 작업을 수행하지만 다시 실행하면 (4 행 영향) 등이 표시 될 때까지 (0 행 영향) 이것은 다소 의심스럽고 여기에 나에게 가장 잘 맞는 것입니다. 거의 동일하지만 한 번에 작동합니다. 솔루션을 편집했습니다.
Nassim

1
@ Nassim : MySQL에서 완벽하게 작동하기 때문에이 답변과 다른 것을해야합니다.
Lawrence Dol

3
나와 같이 혼란스러워하는 사람에게는 MySQL에서 NULL이 NULL과 같지 않기 때문에 NULL 비교 용어가 필요합니다. 관련 열이 NULL이 아닌 경우이 용어를 생략 할 수 있습니다.
Ian

3
예, 허용 된 답변은 MYSQL 5.7부터 더 이상 유효하지 않으므로 이것이 보편적 인 것이며 임시 테이블 생성도 필요하지 않기 때문에 실제로 허용되는 답변이어야합니다.
that-ben

1
주어진 레코드 (예 : 100을 1로 줄임)의 사본이 여러 개 있고 해당 조건을 가진 많은 레코드가있는 경우 매우 느림. 대신 stackoverflow.com/a/4685232/199364 를 권장하십시오 . IMHO, 항상 연결된 접근법을 사용하십시오. 본질적으로 빠른 기술입니다.
ToolmakerSteve

78

MySQL에는 삭제하는 테이블을 참조하는 데 제한이 있습니다. 다음과 같은 임시 테이블을 사용하여 해결할 수 있습니다.

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

의견에 대한 Kostanos의 제안에서 :
위의 유일한 느린 쿼리는 데이터베이스가 매우 큰 경우 DELETE입니다. 이 쿼리는 더 빠를 수 있습니다.

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

3
@andomar, where 절의 필드 중 하나가 null을 포함하는 경우를 제외하고는 잘 작동합니다. 예 : sqlfiddle.com/#!2/983f3/1
코더

1
Insert SQL은 비용이 많이 듭니까? MySQL 데이터베이스에서 시간이 초과되어 궁금합니다.
Cassio 2016 년

4
큰 데이터베이스가있는 경우 여기에서 유일하게 느린 쿼리는 삭제합니다. 이 쿼리는 더 빠를 수 있습니다.DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos

@Kostanos뿐만 아니라 임시 테이블 DELETE에도 INSERT시간이 오래 걸렸습니다. 따라서 tmp 테이블의 인덱스 create index tmpTable_id_index on tmpTable (id)는 적어도 나에게 많은 도움이 될 수 있습니다.
Jiezhi.G

1
테이블이 크면 다음과 같이 인덱스를 추가하는 것이 create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke

44

는 IF IGNORE문 내 경우처럼 작동하지 않습니다, 당신은 문 아래를 사용할 수 있습니다 :

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;

1
외래 키 제약 조건이있는 innoDB 설정이 있으면 효과적입니다.
magdmartin

@ magdmartin이지만 외계 제약 조건으로 인해 테이블 ​​삭제가 방지되지 않습니까?
Basilevs

1
IGNORE 진술은 저에게 효과적이지 않으며 이것은 5 백만 건의 기록을 제거하는 데 효과적이었습니다. 건배.
Mauvis Ledford

32

MySQL 테이블에서 복제본을 삭제하는 것은 일반적인 문제이며, 사전에 그러한 복제본을 피하기 위해 제약 조건이 누락 된 결과입니다. 그러나이 공통적 인 문제는 일반적으로 특정 접근 방식이 필요한 특정 요구 사항과 함께 제공됩니다. 접근 방식은 예를 들어 데이터의 크기, 유지해야 할 복제 된 항목 (일반적으로 첫 번째 또는 마지막 항목), 유지할 인덱스가 있는지 또는 추가 작업을 수행할지 여부에 따라 달라야합니다. 복제 된 데이터에 대한 조치.

테이블 UPDATE를 수행 할 때 FROM 원인에서 동일한 테이블을 참조 할 수없는 것과 같이 MySQL 자체에도 몇 가지 특성이 있습니다 (MySQL 오류 # 1093이 발생 함). 이 제한은 임시 테이블과 함께 내부 쿼리를 사용하여 극복 할 수 있습니다 (위의 일부 접근 방식에서 제안한대로). 그러나이 내부 쿼리는 빅 데이터 소스를 처리 할 때 특히 잘 수행되지 않습니다.

그러나 복제본을 제거하는 더 나은 방법이 존재하는데, 이는 효율적이고 신뢰할 수 있으며 다른 요구에 쉽게 적용 할 수 있습니다.

일반적인 아이디어는 새로운 임시 테이블을 작성하는 것입니다. 일반적으로 중복을 피하기 위해 고유 제한 조건을 추가하고 중복을 처리하면서 이전 테이블의 데이터를 새 테이블에 삽입합니다. 이 접근 방식은 간단한 MySQL INSERT 쿼리에 의존하고, 추가 복제를 피하기위한 새로운 제약 조건을 생성하며, 내부 쿼리를 사용하여 복제본과 메모리에 보관해야하는 임시 테이블을 검색 할 필요가 없도록합니다 (따라서 빅 데이터 소스에도 적합).

이것이 달성 될 수있는 방법입니다. 다음과 같은 열 이있는 테이블 employee 가 있다고 가정합니다 .

employee (id, first_name, last_name, start_date, ssn)

중복 ssn 열이 있는 행을 삭제하고 첫 번째 항목 만 찾도록하려면 다음 프로세스를 수행 할 수 있습니다.

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

기술 설명

  • 1 번 줄 은 직원 테이블 과 정확히 동일한 구조로 새로운 tmp_eployee 테이블을 만듭니다.
  • 2 번 줄은 새로운 tmp_eployee 테이블에 UNIQUE 제약 조건을 추가하여 더 이상 중복되지 않도록합니다.
  • 3 번 줄 은 중복 된 항목을 무시하고 새 직원 항목을 새 tmp_eployee 테이블에 삽입하여 id로 원래 직원 테이블을 스캔 합니다.
  • 4 번째 줄은 새 직원 테이블이 중복없이 모든 항목을 보유하고 이전 데이터의 백업 복사본이 backup_employee 테이블 에 유지 되도록 테이블 이름을 바꿉니다.

이 방법을 사용하면 1.6M 레지스터가 200 초 이내에 6k로 변환되었습니다.

Chetan 은이 프로세스에 따라 다음을 실행하여 모든 복제본을 빠르고 쉽게 제거하고 고유 한 제약 조건을 만들 수 있습니다.

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

물론이 프로세스는 중복을 삭제할 때 다른 요구에 맞게 조정될 수 있습니다. 다음은 몇 가지 예입니다.

✔ 첫 번째 항목 대신 마지막 항목을 유지하기위한 변형

때로는 첫 번째 항목 대신 마지막으로 복제 된 항목을 유지해야 할 때가 있습니다.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • 3 번 라인에서 ORDER BY id DESC 절은 마지막 ID가 나머지 ID보다 우선 순위를 갖도록합니다.

✔ 복제본에 대한 일부 작업 수행에 대한 변형 (예 : 발견 된 복제본 수 계산)

발견 된 중복 항목에 대해 추가 처리를 수행해야하는 경우가 있습니다 (예 : 중복 수 유지).

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • 3 번 라인에는 새로운 열 n_duplicates 가 생성됩니다.
  • 4 번 라인에서 INSERT INTO ... ON DUPLICATE KEY UPDATE 쿼리는 중복이 발견 될 때 추가 업데이트를 수행하는 데 사용됩니다 (이 경우 카운터 증가) INSERT INTO ... ON DUPLICATE KEY UPDATE 쿼리는 발견 된 중복에 대해 다른 유형의 업데이트를 수행하는 데 사용됩니다.

✔ 자동 증분 필드 ID 재생성에 대한 변형

때때로 우리는 자동 증분 필드를 사용하며 가능한 한 인덱스를 작게 유지하기 위해 중복 삭제를 활용하여 새 임시 테이블에서 자동 증분 필드를 재생성 할 수 있습니다.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • 3 번 라인에서, 테이블의 모든 필드를 선택하는 대신 id 필드는 건너 뛰어 DB 엔진이 자동으로 새로운 필드를 생성합니다

✔ 추가 변형

원하는 동작에 따라 많은 추가 수정도 가능합니다. 예를 들어, 다음 쿼리는 두 번째 임시 테이블을 사용하여 1) 첫 번째 항목 대신 마지막 항목을 유지합니다. 그리고 2) 발견 된 사본에 대한 카운터를 증가시킨다; 또한 3) 자동 증분 필드 ID를 재생성하면서 입력 순서는 이전 데이터와 동일하게 유지합니다.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;

27

또 다른 해결책이 있습니다.

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...

4
6 개월 전에 제출 한 @rehriff의 답변과 다른 점은 무엇입니까?
Lawrence Dol

@LawrenceDol 좀 더 읽기 쉬우 며 대답 할 때 그의 대답이 같지 않다고 생각하고 그의 대답이 편집되었다고 생각합니다.
Mostafa -T

1
흠. 레코드 수가 크지 않은 경우 시간이 너무 오래 걸립니다!
SuB

8

많은 수의 레코드가있는 큰 테이블이 있으면 위의 솔루션이 작동하지 않거나 너무 많은 시간이 걸립니다. 그런 다음 다른 해결책이 있습니다

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;

6

SQLServer에 대한이 쿼리 스 니펫이 있지만 거의 변경하지 않고 다른 DBMS에서 사용할 수 있다고 생각합니다.

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

이 쿼리는 중복 된 행의 ID가 가장 낮은 행을 제거하지 않는다는 것을 잊었습니다. 이것이 효과가 있다면이 쿼리를 시도하십시오.

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

그룹의 사본이 두 개 이상인 경우에는 작동하지 않습니다.
세상에 조랑말

11
불행히도, MySQL은 당신이 삭제하는 테이블에서 선택할 수 없습니다ERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar

1
"You can't specify target table 'Table' for update in FROM..."오류 를 해결하려면 다음 DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)을 사용하십시오. 이렇게하면 MySQL이 임시 테이블을 생성합니다. 그러나 큰 데이터 세트의 경우 속도가 매우 느립니다 ...이 경우 Andomar의 코드를 권장합니다.이 코드는 훨씬 빠릅니다.
lepe

6

가장 빠른 방법은 별도의 행을 임시 테이블에 삽입하는 것입니다. delete를 사용하면 8 백만 행의 테이블에서 중복을 제거하는 데 몇 시간이 걸렸습니다. insert와 distinct를 사용하면 13 분 밖에 걸리지 않았습니다.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  

1
4 번째 줄 TRUNCATE TABLE tableName과 5 번째 줄INSERT INTO tableName SELECT * FROM tempTableName;
Sana

5

이해하기 쉽고 기본 키없이 작동하는 솔루션 :

1) 새로운 부울 열 추가

alter table mytable add tokeep boolean;

2) 복제 된 열과 새 열에 제약 조건을 추가하십시오.

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) 부울 열을 true로 설정하십시오. 이것은 새로운 제약 조건으로 인해 복제 된 행 중 하나에서만 성공합니다.

update ignore mytable set tokeep = true;

4) 유지로 표시되지 않은 행을 삭제하십시오.

delete from mytable where tokeep is null;

5) 추가 된 열을 삭제

alter table mytable drop tokeep;

추가 한 제한 조건을 유지하여 향후 새 복제본이 방지되도록하는 것이 좋습니다.


1
이것은 허용 된 솔루션이 더 이상 작동하지 않는 mysql 5.7에서 실제로 잘 작동했습니다
Robin31

5

DELETE JOIN 문을 사용하여 중복 행 삭제 MySQL은 중복 행을 빠르게 제거하는 데 사용할 수있는 DELETE JOIN 문을 제공합니다.

다음 명령문은 중복 행을 삭제하고 가장 높은 ID를 유지합니다.

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

5

나는 간단한 길을 찾았다. (최신 유지)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;

4

모든 경우에 간단하고 빠릅니다.

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);

오류 코드 : 1055. SELECT 목록의 식 # 2가 GROUP BY 절에 없으며 GROUP BY 절의 열에 기능적으로 의존하지 않는 집계되지 않은 열 'dub.id'를 포함합니다. 이것은 sql_mode = only_full_group_by와 호환되지 않습니다
Swoogan

sql_mode로 "하드 컨트롤"을 비활성화 할 수 있습니다. stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz

4

제목, 회사 및 사이트에 대해 동일한 값을 가진 중복 행이 삭제됩니다. 첫 번째 발생은 유지되고 나머지는 모두 삭제됩니다.

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;

그것은 느린 (5w + 행 잠금 대기 시간 초과)하지만있어 일
yurenchen

3

나는 구글 "mysql에서 복제본을 제거"할 때 마다이 페이지를 계속 방문하지만 InnoDB mysql 테이블이 있기 때문에 IGNORE 솔루션이 작동하지 않습니다.

이 코드는 언제든지 더 잘 작동합니다

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = 정리해야 할 테이블 이름

tableToclean_temp = 생성 및 삭제 된 임시 테이블


2

이 솔루션은 중복을 한 테이블로 이동 하고 고유 항목을 다른 테이블로 이동합니다 .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs

왜 당신은 왜 노조를 취했 SELECT * FROM jobs GROUP BY site_id, company, title, location습니까?
timctran

2

버전 8.0 (2018)부터 MySQL은 마침내 창 기능을 지원 합니다 .

창 기능은 편리하고 효율적입니다. 다음은이 과제를 해결하는 데 사용하는 방법을 보여주는 솔루션입니다.

하위 쿼리에서을 기준으로 그룹 ROW_NUMBER()내 테이블의 각 레코드에 위치를 할당하는 데 사용할 수 있습니다 . 중복이 없으면 레코드에 행 번호가 표시 됩니다. 중복이 있으면 오름차순으로 번호가 매겨집니다 (에서 시작 ).column1/column2id1id1

하위 쿼리에서 레코드의 번호가 올바르게 지정되면 외부 쿼리는 행 번호가 1이 아닌 모든 레코드를 삭제합니다.

검색어 :

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)

1

테이블에서 중복 레코드를 삭제하려면

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

또는

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);

1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;

0

고유 한 열 (예 : COL1, COL2)로 레코드를 복제하려면 COL3을 복제하지 않아야합니다 (테이블 구조에서 고유 한 3 개의 열이 누락되었고 여러 중복 항목이 테이블에 작성되었다고 가정).

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

희망은 개발에 도움이 될 것입니다.


0

TL; TR;

이 문제를 해결하기 위해 크게 설명 된 튜토리얼mysqltutorial.org 사이트 에서 찾을 수 있습니다 .

MySQL에서 중복 행을 삭제하는 방법

세 가지 방법으로 중복 행을 삭제하는 방법이 매우 명확하게 표시됩니다 .

A)DELETE JOIN 문장 사용

B) 중간 테이블 사용

C)ROW_NUMBER() 기능 사용

누군가에게 도움이되기를 바랍니다.


0

id 행에 기본 키를 추가하는 것을 잊어 버리는 테이블이 있습니다. 비록 ID에 auto_increment가 있습니다. 그러나 어느 날 데이터베이스에서 mysql bin 로그를 재생하여 중복 행을 삽입합니다.

중복 행을 제거합니다.

  1. 고유 한 중복 행을 선택하고 내보내십시오.

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. id로 중복 행을 삭제하십시오.

  2. 내 보낸 데이터에서 행을 삽입하십시오.

  3. 그런 다음 id에 기본 키를 추가하십시오.


-2

나는 어떤 레코드를 삭제했는지에 대해 좀 더 구체적이기를 좋아하므로 여기에 내 해결책이 있습니다.

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)

-4

이 코드에서 중복 레코드를 쉽게 삭제할 수 있습니다.

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}

3
이것은 매우 나쁜 양식 데이터베이스 작업입니다 .DB에서 수행해야합니다. 여러분이 더 잘 알고 있기 때문에 php / mysql간에 데이터를 지속적으로 보내는 대신 훨씬 더 빠릅니다.
Max

-4

텍스트 필드 로이 작업을 수행해야했으며 색인에서 100 바이트 제한을 초과했습니다.

열을 추가하고 필드의 md5 해시를 수행하고 변경을 수행 하여이 문제를 해결했습니다.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.