REPEAT · REPLACE · REVERSE — 문자열 변형 완전 정리
문자열 함수 중에서도 REPEAT, REPLACE, REVERSE는 이름 그대로 동작이 직관적이라 외우기는 쉽지만, 정작 "언제 왜 쓰는지"는 잘 안 다뤄지는 함수들이다. 아래 세 줄이 오늘 뜯어볼 원본 쿼리다.
| 쿼리 | 결과 |
|---|---|
REPEAT('이것이', 3) |
이것이이것이이것이 |
REPLACE('이것이 MySQL이다', '이것이', 'This is') |
This is MySQL이다 |
REVERSE('MySQL') |
LqSyM |
REPEAT는 "같은 문자열을 N번 이어붙이라"는 아주 단순한 명령이다. 그런데 이게 실무에서 은근히 자주 등장한다. 구분선을 그리거나, 들여쓰기를 표현하거나, 마스킹 처리할 때 별표(*)를 자릿수만큼 채우는 경우가 대표적이다. 직접 '--------'처럼 손으로 하이픈을 세어 쓰는 대신, REPEAT('-', 20)이라고 쓰면 개수가 바뀌어도 코드를 고칠 필요가 없다.
'')을 반환한다. count가 NULL이면 결과도 NULL이다.REPLACE는 문자열 안에서 일치하는 부분 문자열을 전부 찾아서 다른 문자열로 바꾼다. 정규식처럼 패턴을 쓰는 게 아니라 "이 글자 그대로"를 찾는다는 점이 핵심이다. 그래서 원문에서 등장하는 모든 위치가 한 번에 바뀐다 — 한 번만 바뀌는 게 아니다.
REPLACE ('이것이 MySQL이다', '이것이', 'This is')는 문자열 안에 있는 첫 단어만 바꾸는 게 아니라, '이것이'가 나오는 모든 자리를 바꾼다. 문장에 '이것이'가 두 번 있었다면 두 번 다 바뀐다.REVERSE는 인자를 하나만 받는 가장 단순한 함수지만, 활용도는 의외로 넓다. 회문(palindrome) 판별처럼 "원본과 뒤집은 문자열이 같은가"를 비교하는 로직, 혹은 파일 확장자처럼 문자열 끝부분을 다룰 때 "뒤집고 - 앞에서 자르고 - 다시 뒤집는" 트릭으로 활용된다.
세 함수를 조합해서 쓰다 보면 "지금 어디부터 계산되는 거지?"라는 순간이 반드시 온다. 규칙은 하나다 — 가장 안쪽 괄호부터, 안에서 바깥으로 계산된다. 아래처럼 하나의 파이프라인으로 그려보면 헷갈릴 일이 없다.
REVERSE 역시 이 파이프라인 어느 단계에나 끼워 넣을 수 있다. "치환한 다음 뒤집을지" "뒤집은 다음 치환할지"에 따라 완전히 다른 결과가 나오므로, 조합 전에 항상 순서를 먼저 종이에 그려보는 습관을 들이자.
세 함수는 각자 단순하지만, 중첩하면 더 정교한 문자열 가공이 가능하다. 예를 들어 "치환한 결과를 반복해서 강조 배너를 만든다"거나 "반복해서 만든 패턴을 뒤집어 대칭 무늬를 만든다"는 식이다. 함수를 안에서 밖으로 겹겹이 쌓는 감각을 익히는 게 핵심이다.
세 함수가 단독으로 화면에 노출되는 일은 드물지만, 데이터 가공·리포트 출력·간단한 마스킹 로직에서는 꾸준히 쓰인다.
REPEAT('■', percent/10)로 진행률을 텍스트 막대 그래프처럼 표현. 별도 차트 라이브러리 없이 관리자 페이지에서 즉석 시각화 가능.REPLACE(card_no, SUBSTRING(card_no,5,8), '********')처럼 카드번호 가운데 자리를 별표로 가려서 조회 결과에 노출.REVERSE(val) = val 한 줄로 즉시 판별REPEAT · REPLACE · REVERSE는 혼자 쓰이기보다 LPAD, RPAD, TRIM, SUBSTRING 같은 다른 문자열 함수와 짝지어 쓰일 때가 많다. 역할이 겹치는 듯 보이지만 쓰임새는 분명히 다르므로 간단히 정리해둔다.
| 함수 | 역할 | REPEAT/REPLACE/REVERSE와 차이 |
|---|---|---|
LPAD(str, len, pad) |
왼쪽을 pad로 채워 길이 len에 맞춤 | REPEAT처럼 반복하지만 목표 "길이"가 기준, 문자열 앞쪽만 채움 |
RPAD(str, len, pad) |
오른쪽을 pad로 채워 길이 len에 맞춤 | LPAD과 방향만 반대, 역시 목표 길이가 기준 |
TRIM(str) |
양쪽 공백(또는 지정 문자) 제거 | REPLACE는 "치환"이고 TRIM은 "제거", 목적 자체가 다름 |
SUBSTRING(str, pos, len) |
문자열의 일부만 잘라냄 | REVERSE와 조합해 "뒤에서부터 자르기" 트릭에 자주 함께 쓰임 |
세 함수 모두 사용법은 쉽지만, 프로덕션 쿼리에 넣기 전에 짚어야 할 함정이 있다.
- NULL 전파:
REPEAT(NULL, 3),REPLACE(col, NULL, 'x')모두 결과가 NULL이 된다 —IFNULL()로 방어할지 먼저 결정 - 대소문자 구분: REPLACE는 컬럼/서버의 콜레이션을 따른다.
_ci(case-insensitive) 콜레이션이면 대소문자 구분 없이 치환되므로 의도와 다를 수 있다 - 큰 문자열 반복: REPEAT(str, count)에서 count가 매우 크면
max_allowed_packet한도에 걸릴 수 있다 - REVERSE는 인덱스를 타지 않는다 —
WHERE REVERSE(col) = ...형태는 풀스캔을 유발하므로 WHERE 절에 남발하지 말 것
| 실수 | 증상 | 해결 |
|---|---|---|
| REPLACE의 두 번째·세 번째 인자 순서를 헷갈림 (찾을 값과 바꿀 값을 반대로 씀) | 의도와 정반대로 치환되거나 원본이 그대로 남음 | REPLACE(대상, 찾을값, 바꿀값) 순서를 항상 "찾고→바꾼다"로 암기 |
| REPEAT의 count에 음수나 소수를 넣음 | 에러 없이 조용히 빈 문자열이 반환돼 원인 파악이 늦어짐 | count 계산식에 GREATEST(n, 0)이나 FLOOR()를 씌워 방어 |
| REVERSE로 정렬·검색 조건을 만들면서 인덱스가 걸릴 거라 기대 | 대용량 테이블에서 쿼리가 갑자기 느려짐 | 함수 기반 조건 대신 별도 컬럼에 미리 뒤집은 값을 저장하거나 인덱스를 재설계 |
| REPLACE가 정규식처럼 부분 패턴·와일드카드를 지원한다고 착각 | 특수문자를 넣었는데 문자 그대로 취급돼 치환이 안 됨 | 패턴 매칭이 필요하면 REGEXP_REPLACE()를 사용 |
| NULL이 섞인 컬럼에 REPLACE·REPEAT를 그대로 적용 | 일부 행만 결과가 NULL로 나와 데이터 누락처럼 보임 | IFNULL(col, '')로 먼저 감싸서 NULL 전파를 차단 |
| REPLACE·REPEAT·REVERSE를 중첩할 때 괄호 짝을 잘못 닫음 | 문법 오류이거나, 엉뚱한 인자가 잘못된 함수로 전달됨 | 가장 안쪽 함수부터 하나씩 작성해 결과를 확인한 뒤 바깥 함수로 감싸는 순서로 작성 |
핵심 한 줄 요약
Tags
'php' 카테고리의 다른 글
| MySQL JSON 함수 — JSON_OBJECT·EXTRACT·REPLACE 완전 정리 (0) | 2026.06.28 |
|---|---|
| MySQL SUM(IF()) — 피벗 테이블 만들기 완전 정리 (0) | 2026.06.28 |
| MySQL DATEDIFF · TIMEDIFF — 날짜·시간 차이 완전 정리 (0) | 2026.06.28 |
| MySQL ADDDATE · SUBDATE — 날짜 더하기·빼기 완전 정리 (0) | 2026.06.27 |
| MySQL CONCAT_WS — 구분자 지정 문자열 연결 완전 정리 (0) | 2026.06.27 |
왕진 블로그

댓글