본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

MySQL SUBSTRING · SPACE · SUBSTRING_INDEX — 문자열 추출 완전 정리

by 왕진 2026. 6. 27.
반응형

 

 

Database · MySQL

MySQL SUBSTRING · SPACE · SUBSTRING_INDEX —
문자열 추출 완전 정리

위치 기반 부분 문자열 추출, 공백 채우기, 구분자 기준 분리까지
시작 오늘 분석할 코드

문자열에서 원하는 부분만 잘라내는 작업은 실무에서 아주 자주 나온다. 이메일에서 도메인만 뽑거나, 파일 경로에서 확장자만 뽑거나, 주민번호에서 생년월일만 뽑는 식이다. 아래 세 줄의 SQL이 그 핵심 도구 3종 — SPACE, SUBSTRING, SUBSTRING_INDEX를 보여준다.

SELECT CONCAT('이것이', SPACE(10), 'MySQL이다'); -- '이것이 MySQL이다' (공백 10칸이 그대로 삽입된다) SELECT SUBSTRING('대한민국만세', 3, 2); -- 3번째 글자부터 2글자 → '민국' SELECT SUBSTRING_INDEX('cafe.naver.com', '.', 2), -- '.' 기준 왼쪽에서 2번째 구분자까지 → 'cafe.naver' SUBSTRING_INDEX('cafe.naver.com', '.', -2); -- '.' 기준 오른쪽에서 2번째 구분자까지 → 'naver.com'
실제 결과 미리보기
실행한 식 반환값
CONCAT('이것이', SPACE(10), 'MySQL이다') 이것이          MySQL이다
SUBSTRING('대한민국만세', 3, 2) 민국
SUBSTRING_INDEX('cafe.naver.com', '.', 2) cafe.naver
SUBSTRING_INDEX('cafe.naver.com', '.', -2) naver.com
용어 용어 정리
SUBSTRING문자열의 특정 위치에서 지정한 길이만큼 잘라내는 함수. MID라는 별칭으로도 동작한다.
pos추출을 시작할 위치(position). MySQL 문자열 인덱스는 0이 아니라 1부터 시작한다.
len시작 위치부터 몇 글자를 가져올지 지정하는 길이(length). 생략하면 끝까지 가져온다.
SUBSTRING_INDEX특정 구분자(delimiter)를 기준으로 문자열을 나눈 뒤, 앞쪽 혹은 뒤쪽 일부만 반환하는 함수.
delimiter문자열을 나누는 기준 문자. SUBSTRING_INDEX에서 두 번째 인자로 넘긴다. (예: '.', ',', '-')
SPACE(n)공백 문자 n개로 이루어진 문자열을 생성하는 함수. 주로 CONCAT과 함께 쓰인다.
음수 인덱스SUBSTRING의 pos나 SUBSTRING_INDEX의 count에 음수를 넣으면, 문자열의 "끝"을 기준으로 거꾸로 센다.
1-based배열이나 프로그래밍 언어 대부분은 0부터 세지만, SQL 문자열 함수는 1부터 센다는 관례.
LEFT / RIGHTSUBSTRING의 특수한 형태로, 각각 문자열의 맨 앞/맨 뒤에서 고정 길이만 잘라내는 단축 함수.
CONCAT여러 문자열(또는 함수 반환값)을 하나로 이어붙이는 함수. SPACE와 자주 함께 쓰인다.

1 SPACE(n) — 공백 문자열 만들기
왜 공백을 함수로 만드는가?

SPACE(10)은 공백(스페이스) 문자 10개로 이루어진 문자열을 반환한다. 단독으로 쓰이기보다는 CONCAT과 조합해서, 두 문자열 사이에 일정한 간격을 강제로 삽입하는 용도로 쓰인다. 문자열 리터럴 안에 스페이스바를 여러 번 눌러 넣는 것보다, SPACE(n)으로 개수를 숫자로 명시하는 편이 코드 리뷰에서 "몇 칸인지"가 한눈에 드러나 가독성이 좋다.

※ 화면 정렬이 목적이라면 SPACE보다 애플리케이션 단(HTML/CSS의 white-space, padding) 처리가 더 안전하다. HTML은 연속 공백을 하나로 축약해버리기 때문에, SQL에서 만든 여러 칸 공백이 브라우저에서는 한 칸처럼 보일 수 있다.

실무에서는 SPACE를 웹 화면보다, 고정폭 텍스트 리포트나 콘솔 출력에서 열 너비를 맞추는 용도로 더 자주 사용한다는 점도 함께 기억해두면 좋다.


2 SUBSTRING(str, pos, len) — 1-based 인덱스의 원리
왜 1부터 세는가?

SUBSTRING('대한민국만세', 3, 2)는 3번째 글자부터 2글자, 즉 '민'과 '국'을 반환해 '민국'이 나온다. 여기서 중요한 건 "3번째"가 PHP·JavaScript식으로 인덱스 2(0부터 셀 때)를 의미하는 게 아니라, 진짜 사람이 세는 방식 그대로 1번째 '대', 2번째 '한', 3번째 '민'이라는 점이다. SQL 표준 자체가 문자열·컬럼 위치를 1-based로 정의하기 때문에, MySQL의 SUBSTRING·LOCATE·INSTR 계열 함수 전부가 이 규칙을 따른다.

SUBSTRING('대한민국만세', 3, 2) 문자열: 대(1) 한(2) 민(3) 국(4) 만(5) 세(6) pos=3 부터 len=2 개 → '민국'
※ len이 실제 남은 글자 수보다 크면 에러가 나지 않고, 그냥 있는 만큼만 반환한다. SUBSTRING('민국', 1, 100)은 여전히 '민국'을 반환할 뿐 예외를 던지지 않는다.

3 pos 생략과 음수 pos — 시작점을 다르게 잡는 법
왜 생략과 음수를 지원하는가?

길이(len) 인자를 생략하면 SUBSTRING(str, pos) 형태로 pos부터 문자열 끝까지 전부 가져온다. "몇 글자인지 모르지만 여기서부터 끝까지"가 필요할 때 매번 LENGTH()를 계산해서 len에 넣을 필요가 없다는 뜻이다. 또한 pos에 음수를 넣으면 문자열의 맨 끝을 기준으로 거꾸로 센다. SUBSTRING('대한민국만세', -2)는 끝에서 2번째 글자부터 끝까지, 즉 '만세'를 반환한다.

※ "뒤에서 N글자만 잘라내고 싶다"는 요구는 RIGHT(str, N) 함수로도 동일하게 처리할 수 있다. SUBSTRING(str, -N)RIGHT(str, N)은 대부분 같은 결과를 낸다 — 어느 쪽이 더 의도가 명확히 읽히는지로 고르면 된다.
호출 형태 동작 '대한민국만세' 결과
SUBSTRING(str, 3, 2) 3번째부터 2글자 '민국'
SUBSTRING(str, 3) 3번째부터 끝까지 (len 생략) '민국만세'
SUBSTRING(str, -2) 끝에서 2번째부터 끝까지 '만세'
SUBSTRING(str, -4, 2) 끝에서 4번째부터 2글자 '민국'

 

반응형

 

4 SUBSTRING_INDEX(str, delim, N) — 구분자 기준 왼쪽 추출
왜 위치가 아니라 구분자로 자르는가?

'cafe.naver.com'처럼 도메인 문자열은 매번 글자 수가 다르기 때문에, SUBSTRING(str, pos, len)처럼 고정된 위치·길이로는 잘라낼 수 없다. 이럴 때 쓰는 것이 SUBSTRING_INDEX다. SUBSTRING_INDEX('cafe.naver.com', '.', 2)는 '.'을 구분자로 삼아 왼쪽에서부터 세어 2번째 '.'가 나오기 "직전"까지, 즉 'cafe.naver'를 반환한다. N이 양수면 항상 왼쪽(앞)에서부터 계산한다.

'cafe.naver.com' → '.' 로 나누면 ['cafe', 'naver', 'com'] SUBSTRING_INDEX(str, '.', 2) → 앞에서 2조각 → 'cafe.naver'

5 SUBSTRING_INDEX 음수 N — 오른쪽에서 거꾸로 세기
왜 음수로 방향을 바꾸는가?

N에 음수를 넣으면 기준이 오른쪽(끝)으로 뒤집힌다. SUBSTRING_INDEX('cafe.naver.com', '.', -2)는 오른쪽에서부터 2조각, 즉 'naver.com'을 반환한다. "왼쪽 몇 글자"가 아니라 "구분자 몇 개를 기준으로 어느 방향에서 자를지"가 핵심이라, 도메인의 최상위 2단계만 뽑거나(-2), 파일 경로의 마지막 폴더명만 뽑는(-1) 식으로 아주 유용하게 쓰인다.

※ 확장자만 뽑고 싶으면 SUBSTRING_INDEX('report.final.pdf', '.', -1)'pdf'처럼 N=-1을 쓴다. 반대로 확장자를 뺀 파일명만 필요하면 SUBSTRING_INDEX(str, '.', 1)처럼 N=1을 쓴다 (단, 파일명에 '.'이 여러 개면 첫 조각만 남는다는 점에 주의).
동작 순서를 단계별로 뜯어보면
1
구분자로 문자열을 조각낸다'cafe.naver.com' → '.'로 나누면 ['cafe', 'naver', 'com'] 3조각
2
N의 부호로 방향을 정한다N이 양수면 왼쪽(앞)에서, 음수면 오른쪽(뒤)에서 센다
3
|N|개의 조각을 그 방향으로 이어붙인다N=-2 → 뒤에서 2조각 'naver'+'com' → 'naver.com'
4
구분자 자체는 결과에 그대로 포함된다조각을 자르기만 할 뿐, '.'을 지우지 않고 다시 이어붙여 반환한다

6 실전 조합 — SUBSTRING vs SUBSTRING_INDEX vs LEFT/RIGHT
어떤 상황에 어떤 함수를 쓰는가?

세 함수는 서로 대체 가능한 상황이 많아 헷갈리기 쉽다. 기준을 "위치(숫자)로 자르는가, 구분자(패턴)로 자르는가"로 나누면 선택이 쉬워진다. 위치가 고정돼 있으면(예: 주민번호 앞 6자리 = 생년월일) SUBSTRING·LEFT·RIGHT를 쓰고, 위치가 매번 달라지고 구분자만 고정돼 있으면(예: 이메일의 '@' 뒤 도메인) SUBSTRING_INDEX를 쓴다.

위치 기반 — SUBSTRING / LEFT / RIGHT
길이가 항상 일정한 데이터에 적합.
예: LEFT(주민번호, 6) → 생년월일 6자리
예: RIGHT(전화번호, 4) → 뒷자리 4자리
구분자 기반 — SUBSTRING_INDEX
길이가 매번 다른 데이터에 적합.
예: SUBSTRING_INDEX(이메일, '@', -1) → 도메인
예: SUBSTRING_INDEX(경로, '/', -1) → 파일명
-- 이메일에서 도메인만 추출하는 실전 예 SELECT SUBSTRING_INDEX('user01@naver.com', '@', -1); -- 'naver.com' -- 파일 경로에서 파일명만 추출 SELECT SUBSTRING_INDEX('/var/www/upload/photo.jpg', '/', -1); -- 'photo.jpg'
세 함수 한눈에 비교
함수 자르는 기준 대표 용도
LEFT(str, n) 앞에서부터 고정 길이 주민번호 앞 6자리, 우편번호 앞자리
RIGHT(str, n) 뒤에서부터 고정 길이 전화번호 뒷자리, 카드번호 뒷자리
SUBSTRING(str, pos, len) 임의의 시작 위치 + 길이 고정 서식 문자열의 중간 구간 추출
SUBSTRING_INDEX(str, d, n) 구분자 기준 조각 개수 이메일 도메인, 파일 확장자, URL 경로

7 자주 하는 실수
실수 증상 해결
pos에 0을 넣음 빈 문자열이 반환돼 원인을 못 찾음 MySQL은 1-based이므로 pos는 반드시 1부터 시작. 0은 유효한 위치가 아니다
len을 음수로 넣음 SUBSTRING(str, pos, -3)이 빈 문자열 반환 len(길이)은 음수를 지원하지 않는다. 방향을 바꾸려면 len이 아니라 pos에 음수를 써야 한다
SUBSTRING_INDEX의 N을 문자 개수로 착각 기대한 글자 수만큼 안 잘리고 이상한 값이 나옴 N은 "글자 수"가 아니라 "구분자 조각 개수" 기준이다. 구분자가 몇 번 나오는지부터 세어야 한다
구분자가 문자열에 없는 경우를 고려 안 함 SUBSTRING_INDEX가 원본 문자열 전체를 그대로 반환 구분자가 없으면 자르지 않고 원본을 그대로 반환하는 게 정상 동작. NULL이 아니므로 결과 검증 로직이 필요하면 별도 분기 처리
멀티바이트(한글) 글자 수를 바이트 수로 착각 한글 포함 문자열에서 SUBSTRING 결과가 깨지거나 예상과 다름 SUBSTRING은 바이트가 아니라 문자(character) 단위로 센다. 단, 컬럼의 charset이 utf8mb4 등으로 올바르게 설정돼 있어야 이 규칙이 정확히 적용된다
SPACE로 만든 공백이 화면에서 사라짐 HTML로 렌더링하면 여러 칸 공백이 한 칸으로 보임 HTML은 연속 공백을 축약한다. 정렬 목적이면 SQL의 SPACE보다 CSS의 padding/white-space를 쓰는 게 안전하다
SUBSTRING_INDEX의 N=0을 사용 빈 문자열이 반환돼 로직 오류처럼 보임 N=0은 "0조각"을 의미하므로 항상 빈 문자열이 정상 결과다. 최소 단위는 1 또는 -1부터 시작한다

정리하면 위치가 고정이면 SUBSTRING, 구분자가 고정이면 SUBSTRING_INDEX, 앞뒤 글자 수가 고정이면 LEFTRIGHT가 더 읽기 쉽다.

핵심 한 줄 요약

SPACE(n)공백 n개 문자열 생성, 주로 CONCAT과 조합
SUBSTRING(str, pos, len)위치(1-based) 기반 부분 문자열 추출, len 생략 시 끝까지
pos 음수문자열 끝을 기준으로 거꾸로 위치 지정
SUBSTRING_INDEX(str, delim, N)구분자 기준 왼쪽(N양수)/오른쪽(N음수) 조각 추출
선택 기준길이 고정 → SUBSTRING/LEFT/RIGHT, 길이 가변+구분자 고정 → SUBSTRING_INDEX
len 초과 / N=0len이 남은 글자보다 커도 에러 없이 있는 만큼만 반환, N=0은 빈 문자열

Tags

#MySQL #SUBSTRING #SUBSTRING_INDEX #SPACE #문자열추출 #부분문자열 #CONCAT #LENGTH #SQL #데이터베이스 #DB #문자열함수 #쿼리 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
MySQL, SUBSTRING, SUBSTRING_INDEX, SPACE, 문자열추출, 부분문자열, CONCAT, LENGTH, SQL, 데이터베이스, DB, 문자열함수, 쿼리, 웹개발, 티스토리
반응형

댓글