6. 정리
중복 정리는 키를 정하고, 찾고, 백업하고, 한 건만 남기고 지우고, 제약으로 막는 순서입니다. 탐지는 GROUP BY 키 HAVING COUNT(*) > 1 로 중복 키와 건수를, COUNT(*) OVER (PARTITION BY 키) 로 중복 행 전체를 봅니다. 사실상 중복은 LOWER(TRIM(email)), REPLACE(phone, '-', '') 같은 정규화 키로 찾습니다.
NULL 은 GROUP BY 에서는 한 그룹이고 = 비교로는 같지 않습니다. NULL 이 가능한 컬럼 하나를 키로 삼으면 서로 다른 행이 중복으로 잡히므로 제외하거나 다른 컬럼과 함께 키를 만듭니다.
표준 삭제는 DELETE FROM member WHERE id NOT IN (SELECT MIN(id) ... GROUP BY 키) 입니다. 남길 기준을 바꾸려면 ROW_NUMBER() OVER (PARTITION BY 키 ORDER BY ...) 로 대상 id 를 뽑아 WHERE id IN (...) 에 씁니다. NOT IN 서브쿼리에 NULL 이 섞이면 0건이 되는 함정은 중급 02 와 같습니다.
DB별 관용구는 Oracle·Tibero 의 ROWID, MSSQL 의 CTE 삭제, MySQL 의 자기 조인 DELETE 입니다. MySQL 은 삭제 대상 테이블을 서브쿼리에 직접 쓰면 ERROR 1093 이 나서 파생 테이블로 감쌉니다. 백업은 Oracle·MySQL 이 CREATE TABLE ... AS SELECT, MSSQL 이 SELECT ... INTO 입니다.
재발 방지는 정리 후 UNIQUE 제약이고, 정규화 키는 Oracle 함수 기반 유니크 인덱스, MySQL 8.0.13 함수 인덱스, MSSQL 계산 열과 유니크 인덱스로 겁니다. MSSQL 은 UNIQUE 에 NULL 을 하나만 허용하므로 필터 인덱스를 씁니다. 다음 레슨은 여러 문장을 하나로 묶어 실패하면 되돌리는 트랜잭션 기초를 다룹니다.