MariaDB 강좌 / 문자열 다루기: 연결·추출·치환·길이
문자열 함수는 글자를 연결·추출·치환하거나 길이를 계산해 조회 결과를 가공합니다. CONCAT·SUBSTRING·REPLACE·CHAR_LENGTH를 목적에 맞게 선택하되, NULL 처리와 문자 수·바이트 수를 구분해야 원본 의미를 훼손하지 않습니다.
연결·추출·치환의 역할 나누기
상품명과 분류를 한 줄로 보여 주는 일, 코드의 일부를 꺼내는 일, 전화번호 구분자를 제거하는 일은 서로 다른 작업입니다. 문자열 함수를 SELECT에 사용하면 출력값이 계산될 뿐 저장된 상품명이 자동으로 수정되지는 않습니다. 먼저 무엇을 원본으로 보관하고 무엇을 화면 표시로 만들지 정하세요. 함수 입력이 담기는 열의 저장 조건은 문자열 타입 선택하기: CHAR·VARCHAR·TEXT, 누락값의 의미를 보존하는 기준은 NULL을 올바르게 비교하기: IS NULL·COALESCE과 함께 확인하세요.
| 함수 | 용도 | 중요한 기준 |
|---|---|---|
| CONCAT | 문자열 이어 붙이기 | 일반 모드에서 인수에 NULL이 있으면 결과 NULL |
| CONCAT_WS | 구분자로 연결 | NULL 인수는 건너뛰지만 빈 문자열은 유지 |
| SUBSTRING | 위치와 길이로 추출 | 첫 문자 위치는 1 |
| REPLACE | 일치하는 부분 문자열 치환 | 행을 대체하는 REPLACE 문과 별개 |
| CHAR_LENGTH / LENGTH | 문자 수 / 바이트 수 | 멀티바이트 문자에서 서로 다름 |
연습 데이터를 준비하고 표시용 문자열 만들기
학습용 MariaDB 서버의 shopcourse에 course_user로 접속합니다. 명령줄 클라이언트와 UTF-8 SQL 파일 실행 방법대로 코드를 UTF-8 파일에 저장하고 SOURCE C:/mariadb-lab/lesson.sql;처럼 실제 파일 경로로 실행할 수 있습니다. SQL 문은 운영체제 터미널이 아닌 MariaDB 연결 안에서 실행합니다.
먼저 SELECT VERSION(), DATABASE();와 SHOW TABLES;로 대상 서버·DB·이름 중복을 확인합니다. 아래 products_19_lab는 이 글의 독립된 연습용 이름입니다. 이미 존재하면 정의와 행을 확인하고, 보관할 자료가 없는 이 글의 실습 테이블임이 확실할 때만 마지막 절의 정리 순서로 지운 뒤 다시 만듭니다. 기존 강좌의 동명 없는 테이블이나 운영 데이터는 삭제하지 않습니다.
USE shopcourse; CREATE TABLE products_19_lab ( product_id INT NOT NULL AUTO_INCREMENT, product_name VARCHAR(100) NOT NULL, category VARCHAR(30) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, note VARCHAR(100) NULL DEFAULT NULL, PRIMARY KEY (product_id), CONSTRAINT ck_p19_price CHECK (price >= 0), CONSTRAINT ck_p19_stock CHECK (stock >= 0) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO products_19_lab (product_id,product_name,category,price,stock,note) VALUES (1, '노트', '문구', 3500.00, 20, NULL), (2, '볼펜', '문구', 1500.00, 0, ''), (3, '머그컵', '생활', 8000.00, 12, '선물 포장'), (4, '스탠드', '생활', 25000.00, 5, NULL), (5, '파일', '문구', 1500.00, 50, ''), (6, '케이블', '전자', 8000.00, 0, '호환 확인');
상품 메모에는 NULL과 빈 문자열이 함께 있습니다. 같은 입력에 서로 다른 연결 함수를 적용하면 표시 정책이 드러납니다. NULL과 빈 문자열 비교 실습에서 두 상태의 차이를 먼저 확인할 수 있습니다.
SELECT product_id, CONCAT(product_name,' / ',category) AS label,
CONCAT_WS(' / ',product_name,note) AS note_label
FROM products_19_lab ORDER BY product_id;
첫 상품의 label은 노트 / 문구이고 note_label은 노트입니다. note가 NULL인 경우 CONCAT_WS가 해당 인수를 생략했기 때문입니다. 반면 볼펜의 메모는 빈 문자열이므로 구분자가 붙은 결과가 될 수 있습니다. 화면에 구분자가 남는다고 NULL 데이터로 바꾸지 말고 빈 메모의 표시 정책을 정해야 합니다.
문자 위치를 기준으로 필요한 부분 꺼내기
SELECT SUBSTRING('MariaDB',1,5), SUBSTRING('MariaDB',-2);
SELECT REPLACE('010-1234-5678','-','') AS normalized_phone;
결과는 Maria, DB, 01012345678입니다. SUBSTRING의 시작 위치는 0이 아니라 1이며 음수 위치는 뒤쪽을 기준으로 계산합니다. 길이는 바이트가 아닌 문자 기준이므로 한글 문자열도 문자 위치로 다룰 수 있습니다. 코드 앞부분을 무조건 자르기 전에 그 위치가 업무상 고정되어 있는지도 확인하세요. SUBSTRING 문법과 위치 규칙을 참고할 수 있습니다.
REPLACE 함수는 일치하는 부분 문자열을 바꿉니다. 문서 전체를 업데이트하는 명령은 아니며, 전화번호에서 구분자를 지운 결과를 식별값으로 저장할지는 별도의 검증이 필요합니다. 국가 번호·내선·앞자리 0 같은 정보를 숫자 변환으로 없애지 않도록 주의합니다.
문자 수와 바이트 수를 비교하기
SELECT CHAR_LENGTH('한글'), LENGTH('한글'),
CHAR_LENGTH('🙂'), LENGTH('🙂');
클라이언트와 문자열이 utf8mb4인 실습에서는 한글은 2문자·6바이트, 이모지는 1문자·4바이트입니다. UI에서 보이는 하나의 기호가 여러 코드 포인트의 조합일 수도 있으므로 CHAR_LENGTH가 언제나 사람이 인식하는 글자 묶음의 수와 같다고 단정하지는 않습니다.
입력 제한을 100자로 정하는 일과 네트워크·저장소의 100바이트를 제한하는 일은 다릅니다. 문자열 타입과 길이 기준을 함께 확인하고, 바이트 수를 임의로 잘라 잘못된 UTF-8 조각을 만들지 않습니다.
NULL·빈 문자열·공백 정리의 차이 확인하기
SELECT CONCAT('노트',NULL),
CONCAT_WS(' / ','노트',NULL,'');
SELECT CONCAT('[',TRIM(' 노트 '),']');
첫 결과는 NULL이며 둘째 결과에는 빈 문자열 때문에 마지막 구분자가 남습니다. TRIM 예제는 양끝의 기본 공백을 제거해 [노트]를 만듭니다. TRIM이 모든 종류의 유니코드 공백이나 문자열 중간 공백까지 제거하는 기능은 아닙니다. 사용자 이름·비밀번호처럼 공백 자체가 의미 있는 값은 일괄 정리하지 않습니다.
문자열 비교에는 열의 정렬 규칙이 영향을 줍니다. 대소문자·악센트·끝 공백을 구분해야 하는 업무에서는 함수만 바꾸기보다 타입과 collation을 함께 검토합니다. MariaDB 문자열 함수 안내에서 함수별 NULL과 변환 동작을 확인하세요.
원본과 가공 결과를 나란히 점검하고 반복하기
새 표시값만 출력하지 말고 기본키·원본 열·가공 열을 함께 조회합니다. 잘린 값이 예상보다 짧으면 위치와 길이를, 연결 결과가 NULL이면 각 인수를, 한글이 깨지면 파일·연결 문자 집합을 확인합니다. 원본을 UPDATE하기 전에는 SELECT로 가공 규칙을 검증하고 복구 가능한 변경 절차를 따르세요.
반복하기 전 현재 DB와 실제 정의·행을 확인하고 필요한 자료를 백업합니다. 보관할 데이터가 없는 이 글의 전용 실습 객체만 아래 순서로 정리합니다. 외래키가 있으면 자식부터 지웁니다. DROP TABLE은 구조와 데이터를 모두 없애며 일반적인 ROLLBACK으로 복원되지 않으므로 취소 가능한 DML 실습과 분리합니다.
DROP TABLE shopcourse.products_19_lab;










