가장 간단하게는 파일명이 중복되지 않을 때 까지 반복문을 사용하여 확인 할 수 있다.
예시 코드입니다.
//java
String orgName = fileObj.getFileName();
String newName = NewNameService.getNewName(fileObj);
int idx = 1;
while(newName != null){
fileObj.setFileName(orgName + "(" + (idx+1).toString() + ")");
newName = NewNameService.getNewName(fileObj);
}
하지만 저는 아래와 같은 생각 때문에 쿼리한번으로 처리 하고자 했습니다.
1. 성능:
- 반복문을 사용하는 경우: 각각의 fileName를 가져와서 (idx)를 붙여서 중복을 확인하고, 존재하지 않는 idx를 찾을 때까지 반복문을 실행해야 합니다. 이는 데이터베이스와 여러 번의 통신을 수행하므로 성능이 저하될 수 있습니다.
- 쿼리를 사용하는 경우: 하나의 쿼리로 중복된 fileName를 확인하고, 최대 idx를 계산하여 바로 새로운 fileName를 생성할 수 있습니다. 이는 데이터베이스와 한 번의 통신만 수행하므로 성능이 개선될 수 있습니다.
2. 안전성:
- 반복문을 사용하는 경우: 여러 번의 통신과 반복문을 통해 중복된 fileName와 최대 idx를 확인하므로, 동시에 동일한 fileName를 처리하는 다른 요청과의 충돌이 발생할 수 있습니다.
- 쿼리를 사용하는 경우: 하나의 쿼리로 중복된 fileName와 최대 idx를 확인하므로, 데이터베이스에서 동시에 수행되는 다른 요청과의 충돌을 최소화할 수 있습니다.
JAVA에서
//java
String newName = NewNameService.getNewName(fileObj);
if(newName != null){
fileObj.setFileName(newName);
}
중복되는 파일 이름뒤에 seq
괄호 없이 숫자 먼저 붙여 보았다.
ex) New 파일이 존재할 때
fileName이 New면 New1반환
ex) New 파일과 New1 파일이 존재할 때
fileName이 New면 New2반환
ex) New1 파일이 존재할 때
fileName이 New1면 New11반환
SELECT
CONCAT (#{fileName}, (
SELECT MAX(CAST(substring(FILENAME, LENGTH(#{fileName})+1) AS INTEGER)) FROM FILELIST
WHERE FOLDER = #{folder} AND FILENAME LIKE CONCAT(#{fileName}, '%'))+ 1) AS seq
FROM FILELIST
WHERE FOLDER = #{folder} AND FILENAME LIKE CONCAT(#{fileName}, '%')
ORDER BY FILENAME DESC limit 1
error) new1234를 했을 때 new12345가 아닌 new1235가 되는 에러가 있었음
중복되는 파일 이름 뒤에 (seq) 붙이기
SELECT IF((SELECT FILENAME FROM FILELIST
WHERE FOLDERID = #{folderId} AND FILENAME = #{fileName}) IS NOT NULL,
(SELECT IFNULL(
(SELECT
CONCAT (#{fileName}, '(', (
SELECT MAX(CAST(REPLACE(REPLACE(REPLACE(FILENAME, #{fileName}, ''), '(', ''), ')', '') AS INTEGER)) FROM UX_FUNCTION
WHERE FOLDERID = #{folderId}
AND FILENAME LIKE CONCAT(#{fileName}, '(', '%', ')')
AND FILENAME REGEXP CONCAT(REPLACE(REPLACE(#{fileName}, '(', '\\('), ')', '\\)' ), '\\([0-9]+\\)$' ))
+ 1, ')') AS seq
FROM FILELIST
WHERE FOLDERID = #{folderId}
AND FILENAME LIKE CONCAT(#{fileName}, '(', '%', ')')
AND FILENAME REGEXP CONCAT(REPLACE(REPLACE(#{fileName}, '(', '\\(' ), ')', '\\)' ), '\\([0-9]+\\)$' )
ORDER BY FILENAME DESC limit 1),
CONCAT(#{fileName}, '(1)'))),
NULL)
예시 1) "New"라는 파일 생성시 database에
"New" 라는 데이터가 있을 때 : "New(1)" 반환
"New", "New(1)" 라는 데이터가 있을 때 : "New(2)" 반환
예시 2) "New(1)"라는 파일 생성시 database에
"New(1)" 라는 데이터가 있을 때 : "New(1)(1)" 반환
"New(1)", "New(1)(1)" 라는 데이터가 있을 때 : "New(1)(2)" 반환
1. IF문
IF(A, B, C)
A가 참이면 B, 아니면 C를 반환합니다.
위의 쿼리에서
A: 입력한 fileName이 존재하는지(not null) 확인
B: fileName(idx)형태의 새 이름
C: NULL
2. 1-B 구문에서 IFNULL
IFNULL (A, B)
A가 NULL이 아니면 A를, NULL이면 B를 반환
위의 쿼리에서
A: fileName(maxidx + 1) 형태의 새 파일이름 반환
B: maxidx를 구할 수 없을 때 ( fileName(idx)형태 데이터 없고, fileName만 있을 때) fileName(1)을 반환
3. 2-A 구문에서
fileName(idx)형태의 데이터 idx가 숫자가 아닌경우를 방지하기 위해 아래 쿼리 대신 REGEXP를 사용
#숫자가 아닌것도 들고 옴
FILENAME LIKE CONCAT(#{fileName}, '(', '%', ')')
#숫자만 들고옴
REGEXP CONCAT(#{fileName}, '\\([0-9]+\\)' )
REGEXP는 정규표현식을 이용할 때 사용한다.
4. 아래 에러에 따른 수정
*위의 코드는 수정한 상태
error) 파일이름에 괄호가 포함되었을 때 REGEXP에서 이렇게 고쳐줘야함.
REGEXP CONCAT('New\\(3\\)', '\\([0-9]+\\)' ))
이걸 스프링매퍼에서 하려면 아래와 같음.
REGEXP CONCAT(REPLACE(REPLACE(#{fileName}, '(', '\\('), ')', '\\)' ), '\\([0-9]+\\)' ))
error) New(1)(3)가 있을 때 New를 입력했을 때 14으로 나옴
#수정전
FILENAME REGEXP CONCAT(#{fileName}, '\\([0-9]+\\)' ))
#수정후
FILENAME REGEXP CONCAT(#{fileName}, '\\([0-9]+\\)$' ))
'$'는 문자열의 끝을 나타내며, 이를 추가하여 숫자 뒤에 다른 문자가 오는 경우를 제외할 수 있습니다.
'SQL > RDBMS' 카테고리의 다른 글
서브 쿼리 ORDER BY (0) | 2023.10.23 |
---|---|
[MariaDB] RECURSIVE 계층 메뉴 구성 (0) | 2023.08.14 |
[MariaDB] 환경 구축 (생성, 삭제, 권한, 백업) (0) | 2023.04.25 |
ORA-01722: 수치가 부적합합니다 (0) | 2023.03.17 |
[mariaDB] 제약 조건(조회, 추가, 수정, 삭제) (0) | 2023.03.17 |