Home

[MySql] SUBSTRING_INDEX를 활용한 Version Update Query

목차

배경

사내에서 다른팀이 관리하는 Table에 데이터를 추가해야하는 경우가 생겼다. 해당 테이블은 특정 API의 Version을 Table에 넣어서 관리하고 있는데, 처음에는 왜 이거를 Table로 관리하지..? 라는 의구심이 생겼었다. 살짝 팀장님께 여쭤보니 AI팀에서 데이터를 분류할때 쓰는 테이블로, 사실 AI팀에서 필요해서 만든 테이블이라고 한다.

하여튼 해당 테이블에 Version을 관리하기 위한 컬럼이 존재하는데 데이터는 10.0.1, 20.1.3 과 같이 유의적 버전(Sementic Versioning) 포맷을 사용하고 있다. API가 변경되면 해당 Version의 수(Patch) 버전을 update해줘야 하는 필요성이 생겼다. 보통 Code를 수정/배포 한 뒤 version을 올려주면 되지 않냐? 라고 생각할 수 있는데.. 내가 작성한 코드는 pub/sub을 통해서 별도의 배포가 필요없이 작성한 코드라서 새로운 함수가 추가되거나 변경되는 경우 Version을 올려주면 된다. 이를 쿼리로 해결할 수 있는 방법이 있나 찾아보다가 SUBSTRING_INDEX 함수를 통해서 해결할 수 있어서 이를 기록으로 남겨놓는다.

문제

일단 테이블 구조를 간단하게 보자.

pkid name version
1 api-1 1.10.7
2 api-2 1.11.3

간단하게 표시하면 위와 같은 구조로 되어 있고, 만약 api-1이 수정되었다면 version을 1.10.7에서 1.10.8로 업데이트 해주면 되는 것이다. 그러면 이를 어떻게 구현할 수 있을까..? 생각해보면 2가지 방법이 존재한다. 첫번째는 해당 Row를 조회한뒤 코드로 Version을 증가시킨 값을 업데이트해주는 방법이고, 다른 하나는 쿼리로 이를 증가시키는 방법이다. 첫번째 방법은 너무 흔한 방법이고 두번째 방법으로 구현하는 방법을 알아보자. 일단 나는 SUBSTRING_INDEX 함수를 써서 구현하였다.

SUBSTRING_INDEX

SUBSTRING_INDEX 함수는 말 그대로 문자열을 JS에서 split 함수와 비슷한 역할을 하는 함수이다. 일단 JS로 결과를 살펴보자.

const version = '1.10.7';
const [major, minor, patch] = version.split('.');

console.log(major, minor, patch);  // 1 10 7

JS의 경우 split함수에 넘긴 구분자로 String을 나눈뒤 이를 배열에 담아 리턴한다. 그러면 SUBSTING_INDEX는 어떻게 될까.?

select SUBSTRING_INDEX('1.10.7', '.', 1);  // 1 리턴
select SUBSTRING_INDEX('1.10.7', '.', 2);  // 1.10 리턴
select SUBSTRING_INDEX('1.10.7', '.', 3);  // 1.10.7 리턴
select SUBSTRING_INDEX('1.10.7', '.', -1); // 7 리턴
select SUBSTRING_INDEX('1.10.7', '.', -2); // 10.7 리턴
select SUBSTRING_INDEX('1.10.7', '.', -3); // 1.10.7 리턴

단순 결과만 봐서는 조금 헷갈릴수 있는데, SUBSTRING_INDEX를 인자를 설명하면 다음과 같다.

SUBSTRING_INDEX(컬럼 Or 문자열, 구분 문자, 인덱스)

여기서 헷갈릴만한 포인트가 바로 인덱스인데, 인데스에 양수를 넣으면 앞에서부터 N(인덱스)위치까지의 값을 보여주고, 음수를 넣으면 뒤에서부터 N(인덱스)위치까지의 값을 보여준다. 즉 1을 넣으면 앞에서부터 값까지 나오고, 2를 넣으면 2번째 인덱스가지 값이 나온다. 다만 split 함수와는 다르게 구분 문자도 같이 보여진다.

그럼 내가 만든 이슈를 다시보자. API가 업데이트 되면 수(patch)를 +1 시켜줘야 하는 것이다. 이를 어떻게 쿼리로 만들 수 있는지 보자.

결론

방법은 간단하다. version 컬럼에 있는 값을 두개로 쪼갠다. 앞은 1.10 과 같이 주.부를 가지고 있는 값이 되고, 뒤는 7로 수를 가지고 있는 값을 구한뒤 이를 숫자로 변환한뒤 +1 해준다음 앞부분과 결합하면 되는 것이다. 말로 설명하니깐 복잡한데 쿼리로 보면 간단하다. 쿼리로 보자

UPDATE METHOD
SET    version = CONCAT(SUBSTRING_INDEX(version, '.', 2), '.', CAST(SUBSTRING_INDEX(version, '.', -1) as signed) + 1),
WHERE  pkid = ?`;

SUBSTRING_INDEX(version, '.', 2) 의 결과는 1.10 이 되고, CAST(SUBSTRING_INDEX(version, '.', -1) as signed) + 1) 결과는 8이 된다. 이 두개를 합쳐야 하는데 중간에 .를 넣야 줘야 해서 중간에 추가해줬다. 이 3개의 문자를 하나로 합친뒤 이를 업데이트 해주면 되는 것이다.

그럼 만약 부(minor)를 얻어오고 싶다면 어떻게 해야 할까..?

이 경우 SUBSTRING_INDEX 함수를 두번 써야 한다.

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('1.10.7', '.', 2), '.', -1)  // 10
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('1.10.7', '.', -2), '.', 1)  // 10

위 쿼리 두개는 일단 결과물은 같은데, 어떻게 자르느냐에 따라 달라지게 된다. 처음 문자열을 자를때 앞에서 2개를 가져온뒤 뒤에서 1개를 가져올지, 아니면 뒤에서 2개를 가져오고 앞에서 1개를 가져올지에 따라 바뀌는 것이다. 결과물은 같으니 무엇을써도 상관 없다.

SUBSTRING_INDEX를 잘 활용하면 복잡하게 코드로 관리하지 않고도 쿼리로 한방에 해결할 수 있다. 이렇게 쉽게 해결 할 수 있는 방법이 있는지 몰라서 힘들게 작업하고 있는 것들이 있을수 있는데.. 무작정 코드로 작성하기 보다, 우선 쿼리로 할 수 있는 방법이 있는지 고민해보는것도 좋을것 같다.

Loading script...