엑셀에서 복사해 붙인 데이터나 웹 폼 textarea 로 들어온 값을 DB에 넣고 나면, 눈에는 안 보이는 탭이나 줄바꿈 문자가 끼어 있는 경우가 꽤 많습니다. 화면에서는 멀쩡해 보이는데 WHERE code = 'A001' 로 찾으면 안 나오고, 길이를 찍어 보면 한두 글자가 더 길게 나오죠. 이럴 때 쓰는 게 MySQL의 REPLACE() 입니다.
REPLACE(문자열, 찾을 문자열, 바꿀 문자열)
찾은 문자열을 전부 바꿉니다. 첫 번째 것만 바꾸는 게 아니라 문자열 안에 있는 것 모두가 대상이고, 대소문자를 구분합니다. 바꿀 문자열에 빈 문자열 '' 을 주면 그냥 삭제가 됩니다. 아래 예제에서 table 은 테이블명, field 는 컬럼명 자리입니다.
문자별 제거 쿼리
보이지 않는 문자는 따옴표 안에 직접 쓰기 어려우니 CHAR(코드) 로 지정합니다. 자주 쓰는 건 세 가지입니다.
| 문자 | 코드 | 쿼리에서 쓰는 형태 |
|---|---|---|
| 탭 (Tab) | 9 | CHAR(9) |
라인피드 (LF, \n) |
10 | CHAR(10) |
캐리지리턴 (CR, \r) |
13 | CHAR(13) |
공백 제거:
update table set field = replace(field, ' ', '');
여기서 착각하기 쉬운 게 있는데, 이 쿼리는 앞뒤 공백만 지우는 게 아니라 문자열 중간의 공백까지 전부 없앱니다. "홍 길동" 이 "홍길동" 이 되는 거죠. 상품코드나 전화번호처럼 공백이 아예 없어야 하는 컬럼이면 괜찮지만, 이름이나 주소에 걸면 데이터가 망가집니다. 양 끝 공백만 정리하려면 TRIM() 을 쓰세요.
update table set field = trim(field);
윈도우 줄바꿈(CR+LF) 제거:
update table set field = replace(field, '\r\n', '');
MySQL 문자열 리터럴 안의 \r, \n 은 이스케이프로 해석되어 실제 CR, LF 문자가 됩니다. 단, 서버가 NO_BACKSLASH_ESCAPES 모드로 돌고 있으면 글자 그대로 백슬래시가 되니, 이때는 아래처럼 CHAR() 방식을 쓰는 게 확실합니다.
탭 제거:
update table set field = replace(field, char(9), '');
라인피드 제거:
update table set field = replace(field, char(10), '');
캐리지리턴 제거:
update table set field = replace(field, char(13), '');
\r\n 을 한 번에 지우는 쿼리는 CR과 LF가 붙어 있을 때만 걸립니다. 맥이나 리눅스에서 만든 데이터처럼 LF만 들어 있는 경우도 있어서, 저는 보통 CR과 LF를 따로 지우는 쪽을 씁니다.
한 번에 여러 문자 지우기
REPLACE 는 결과가 다시 문자열이라 중첩해서 쓸 수 있습니다. 탭·CR·LF를 한 쿼리로 정리하고 마지막에 앞뒤 공백까지 다듬으면 이렇게 됩니다.
update table
set field = trim(replace(replace(replace(field, char(9), ''), char(13), ''), char(10), ''));
같은 방식으로 다른 문자에도 응용할 수 있습니다. 예를 들어 전화번호나 사업자번호에서 하이픈을 빼고 숫자만 저장하고 싶을 때는 이렇게 씁니다.
update table set field = replace(field, '-', '');
UPDATE 전에 꼭 확인할 것
WHERE 없는 UPDATE 는 테이블 전체를 바꿉니다. 저는 먼저 SELECT 로 어떤 행이 영향을 받는지, 바뀐 결과가 어떤지 확인하고 나서 UPDATE 를 돌립니다.
select field, replace(field, char(13), '') as after_value, length(field)
from table
where field like concat('%', char(13), '%');
줄바꿈을 지우는 게 항상 정답은 아니라는 점도 기억해 두면 좋습니다. 게시글 본문이나 메모처럼 줄바꿈이 의미 있는 컬럼에서 CR/LF를 지우면 문단이 한 줄로 붙어 버립니다. 그런 컬럼은 지우는 대신 replace(field, '\r\n', '\n') 처럼 줄바꿈 형식만 통일하는 편이 낫습니다. 그리고 근본적으로는 입력 단계(PHP라면 trim(), VB.NET이라면 String.Trim())에서 정리해서 넣는 게 나중에 덜 고생합니다.
참고: 카레유 블로그