송장번호 컬럼에 번호가 하나 들어 있는데 추가 송장이 생겨서 뒤에 이어 적어야 한다거나, 비고란에 기존 메모를 남긴 채 한 줄을 더 붙이고 싶을 때가 있습니다. UPDATE ... SET 컬럼 = '새값' 으로 하면 기존 내용이 통째로 사라지니, 원래 값을 읽어서 CONCAT 으로 합친 결과를 다시 넣어야 합니다.

UPDATE `job_order` SET `InvoiceNumber` = concat(`InvoiceNumber`, '추가할값') WHERE `uid` = 1

SET 오른쪽의 InvoiceNumber 는 수정되기 전의 값입니다. 그래서 "기존 값 + 추가할값" 이 계산되어 같은 컬럼에 다시 저장됩니다. 프로그램에서 먼저 SELECT 로 값을 읽고, 문자열을 붙이고, 다시 UPDATE 하는 세 단계를 쿼리 한 줄로 끝내는 셈이고, 그 사이에 다른 사용자가 값을 바꿔서 덮어쓰는 일도 생기지 않습니다.

광고

기존 값이 NULL이면 아무것도 안 붙는다

가장 많이 막히는 지점입니다. MySQL의 CONCAT 은 인자 중 하나라도 NULL 이면 결과 전체가 NULL 이 됩니다. 아직 한 번도 값을 넣지 않은 행은 컬럼이 NULL 이라서, 위 쿼리를 실행해도 '추가할값' 이 들어가지 않고 계속 NULL 로 남습니다. 오류도 안 나니 한참 헤매게 되죠. IFNULL 로 빈 문자열을 대신 넣어 주면 해결됩니다.

UPDATE `job_order` SET `InvoiceNumber` = CONCAT(IFNULL(`InvoiceNumber`, ''), '추가할값') WHERE `uid` = 1

구분자를 넣거나 앞에 붙이기

번호를 여러 개 이어 붙이다 보면 경계가 안 보여서 나중에 다시 나누기가 어렵습니다. 쉼표 같은 구분자를 같이 넣는 게 좋은데, 이럴 땐 CONCAT_WS 가 편합니다. 첫 번째 인자가 구분자이고, NULL 인 인자는 건너뛰기 때문에 처음 값이 들어갈 때 앞에 쉼표가 붙지 않습니다.

UPDATE `job_order` SET `InvoiceNumber` = CONCAT_WS(',', `InvoiceNumber`, '추가할값') WHERE `uid` = 1

다만 기존 값이 NULL 이 아니라 빈 문자열('')이라면 CONCAT_WS 도 그 빈 값을 건너뛰지 않아 ,추가할값 처럼 쉼표가 앞에 붙습니다. 빈 문자열과 NULL이 섞여 있는 테이블이라면 NULLIF(InvoiceNumber, '') 로 감싸서 넣으면 둘 다 같은 식으로 처리됩니다. 앞쪽에 붙이고 싶으면 CONCAT('추가할값', InvoiceNumber) 처럼 인자 순서만 바꾸면 됩니다.

주의할 점은 컬럼 길이입니다. VARCHAR(20) 처럼 길이가 정해진 컬럼에 계속 이어 붙이면 언젠가 길이를 넘기는데, SQL 모드에 따라 오류가 나거나 뒤가 잘린 채로 저장됩니다. 값을 계속 누적하는 용도라면 길이를 넉넉히 잡거나, 아예 별도 테이블에 한 줄씩 기록하는 구조가 나중에 검색하기도 편합니다. 그리고 WHERE 조건을 빼먹으면 모든 행에 값이 붙으니 실행 전에 꼭 확인하세요.

같은 값을 두 번 붙이지 않으려면

프로그램에서 버튼을 두 번 누르거나 같은 파일을 다시 올리면, 이미 붙어 있는 송장번호가 한 번 더 붙습니다. 쉼표로 구분해 저장하는 구조라면 FIND_IN_SET 으로 이미 들어 있는지 확인하는 조건을 WHERE 에 같이 걸어 두면 됩니다.

UPDATE `job_order`
SET `InvoiceNumber` = CONCAT_WS(',', NULLIF(`InvoiceNumber`, ''), '추가할값')
WHERE `uid` = 1
  AND FIND_IN_SET('추가할값', IFNULL(`InvoiceNumber`, '')) = 0

이미 있는 값이면 조건에 걸려서 아무 행도 바뀌지 않고, 처음 넣는 값이면 정상적으로 붙습니다. 실행한 뒤 영향받은 행 수가 0인지 1인지를 보면 프로그램 쪽에서 "이미 등록된 번호" 같은 안내를 띄울 수도 있습니다. FIND_IN_SET 은 쉼표를 구분자로 보는 함수라서, 구분자를 다른 문자로 쓰고 있다면 이 방법은 맞지 않습니다. 쉼표 뒤에 공백을 넣어 저장하는 경우(a, b)도 공백까지 값으로 보기 때문에 비교가 어긋납니다.

줄을 바꿔 붙이고 싶을 때

비고란처럼 사람이 읽는 메모라면 쉼표보다 줄바꿈이 낫습니다. 구분자 자리에 '\n' 을 쓰면 MySQL이 줄바꿈 문자로 해석해서 저장합니다. 날짜를 같이 남기고 싶다면 CONCAT(NOW(), ' 추가할값') 처럼 추가할 값을 만들어 넣으면 되고요. 다만 이런 식으로 누적되는 메모가 길어지고 "언제 누가 무엇을 바꿨는지" 를 따로 찾아야 할 정도가 되면, 위에서 말한 대로 이력 테이블을 따로 두는 게 맞습니다.