2012-07-12 1 views
0

데이터베이스에 중복 된 항목을 찾는 방법에 대한 질문은 많이 있지만 문제는 아닙니다.데이터베이스에서 복제본을 찾는 방법은 무엇입니까?

테이블이 약 개 있습니다. 120000 개의 항목. 나는 중복을 찾아야 해. 그들을 발견하기 위해, 나는 같은 구조하는 PHP 스크립트를 사용하여 다음

//get all entries from database 
//loop through them 
    //get entries with greater id 
    //compare all of them with the original one 
    //update database (delete duplicate, update information in linked tables, etc.) 

내 중복 검색 이후의 모든 항목을 통해 루프를 가지고 있기 때문에 초기 쿼리에 이미 모든 중복을 정렬 할 수 없습니다 100 % 유사 항목뿐만 아니라 90 % 유사 항목에도 민감합니다. 나는 그것을 위해 similar_text()를 사용합니다.

첫 번째 루프는 괜찮 았지만 루프 내의 다른 모든 항목을 반복하는 것은 너무 많은 것 같습니다. 120000 개의 항목이 있으면 (120000^2)/2 번의 반복에 가까울 것입니다.

루프 내에서 루프를 사용하는 대신 더 나은 방법이 있어야합니다. 아이디어가 있습니까? in_array() 사용에 대해 생각했지만 90 % 문자열 유사성과 같은 것에 민감하지 않으며 나에게 중복을 찾은 배열 필드를 제공하지 않습니다 - 항목을 업데이트하려면 해당 ID가 필요합니다. 데이터베이스를 올바르게.

아이디어가 있으십니까?

대단히 감사합니다!

찰스

UPDATE 1

필자가 현재 사용하고있는 쿼리는 다음과 같다 :

SELECT a.host_id 
FROM host_webs a 
JOIN host_webs b ON a.host_id != b.host_id AND a.web = b.web 
GROUP BY a.host_id 

그것은 완벽하게 원본과 중복을 보여 주지만, 내가 원본을 제거 할 필요가, 즉 관련 데이터와 함께 처음 발견 된 것입니다. 어떻게해야합니까?

답변

2

을 제거 당신은 그 자체에 테이블을 JOIN 및 SQL에서 모든 작업을 수행 할 수 있습니다 (난 당신이 sa를 알고 당신은 할 수 있다고 생각하지 않지만, 그렇다면 놀랄 것입니다.) 중복을 테스트 할 때 사용하는 모든 열을 JOINON 절에 넣기 만하면됩니다.

SELECT id 
FROM tablename a 
JOIN tablename b ON a.id != b.id AND a.col1 = b.col1 AND a.col2 = b.col2 
GROUP BY id 

col1col2가 중복되는 행의 바로 id의를 반환합니다. 필요한 문자열 비교를이 문자열에 통합 할 수 있습니다. ON 절은 필요한만큼 복잡 할 수 있습니다.예를 들어 :

SELECT id 
FROM tablename a 
JOIN tablename b ON a.id != b.id AND 
    (a.col1 = b.col1 AND (a.col2 = b.col2 OR a.col3 = b.col3)) 
    OR ((a.col1 = b.col1 OR a.col2 = b.col2) AND a.col3 = b.col3) 
    OR (SOUNDEX(a.col1) = SOUNDEX(b.col1) AND SOUNDEX(a.col2) = SOUNDEX(b.col2) AND SOUNDEX(a.col3) = SOUNDEX(b.col3)) 
GROUP BY id 

편집

모든 이후 실제로 쿼리가 web 열이 동일 행을 찾고 함께하고있다, 이것은 단지 중복을 발견하지의 일을 할 것입니다

SELECT b.host_id 
FROM host_webs a 
INNER JOIN host_webs b ON b.web = a.web AND b.host_id > a.host_id 
GROUP BY b.host_id 

I imagi : - 원래 "좋은"기록 host_id 가정 숫자와 "좋은"기록이 가장 낮은 host_id과 하나가 될 것입니다 NE 최종 게임은 여기에 중복을 제거하는 것입니다, 그래서 당신은 용감 느낌이 있다면 당신은 실제로 한 번에 삭제할 수 :

DELETE b.* 
FROM host_webs a 
INNER JOIN host_webs b ON b.web = a.web AND b.host_id > a.host_id 

GROUP BY는이 경우 문제가되지 않기 때문에 DELETE 문에 필요하지 않습니다 하나의 명령.에서 동일한 행을 두 번 이상 시도하고 h 제할 수 있습니다.

+0

고마워요! 검색어가 90 %의 유사성을 허용합니까? – weltschmerz

+0

@Charles 그것은 두 번째 예제가 무엇인지에 대한 90 % 정의 방법에 따라 다릅니다. 이것은'col1','col2','col3' 중 적어도 두 개가 동일하거나 같은 컬럼이 모두 동일한 soundex 점수를 갖는 행을 반환합니다. 유스 케이스에 대한 정확한 쿼리는 유사성을 결정하는 데 사용하는 기준과 열 유형에 따라 다릅니다. – DaveRandom

+0

첫 번째 솔루션을 사용하려고하지만 문제가 하나 있습니다. 발견 한 복제본뿐만 아니라 원본도 제공합니다. 원본을 표시하지 않도록하려면 어떻게해야합니까? 참고 : 중복이 여러 개있을 수 있습니다. 지금 사용하고있는 질문에 대한 질문 편집을보십시오. 고맙습니다! – weltschmerz

0

중복 항목을 1 회 제거하는 경우 SQL 스크립트로 작성하는 것이 더 깔끔한 PHP 스크립트 작성에 신경 쓰지 않아도됩니다.

내가 제일이 작품을 찾을 중복 제거하기위한 일반적인 알고리즘 :
1.
2. 잘라 내기가 원래의 테이블
3. 열이 고유 할 필요는 중에 고유 인덱스를 설정 테이블을 복제를
4. 하나 INSERT IGNORE INTO original_table SELECT * FROM duplicate_table 또는 REPLACE INTO original_table SELECT * FROM duplicate table
5. 고정 연결된 테이블을 사용하여 행을 다시 삽입 - 고아 행 (DELETE x FROM x LEFT JOIN original TABLE ON (...) WHERE original_table.id IS NULL)