[PostgreSQL] 랜덤쿠폰번호 생성 및 중복체크 Function 만들기
개발 중인 프로젝트에서 쿠폰 시스템을 도입하게 되어 기존에 다른 개발자 분이 만들어 둔 sql Function을 plpgsql로 수정하여 보완하였다.
쿠폰 생성 조건
1. 쿠폰번호는 16자리
임시 테이블의 칼럼을 varchar(16)으로 생성하였다. 임시 테이블은 세션이 종료되면 자동으로 drop 되기 때문에 function을 이용할 때 사용하기 좋다. 자릿수는 입맛에 따라 바꿀 수 있다.
2. 영문과 숫자를 이용한 쿠폰번호 생성
이 부분에서 조금 헤맸다.
기존에 generate_series() 함수를 이용해 필요한 쿠폰 갯수만큼의 random() 숫자를 만들어 사용하였는데..
영문자를 넣기 위해서 다양한 방법을 찾던중에 난수에 md5() 함수로 암호화 하는 신박한 내용을 벤치마킹했다.
영문자는 upper() 함수로 대문자로 만들어 유저가 쿠폰번호를 입력할 때도 자동으로 대문자로 치환되도록 했다.
3. 맨앞 4자리는 조직 코드를 이용해 카테고리화
커스터마이징 할 때는 concat() 함수를 이용해서 function 의 return 타입으로 꼭 캐스팅을 해주어야 한다.
4. 기존에 쿠폰 테이블에 등록된 번호인지 중복 체크하는 로직이 필요
기존 Function은 아예 쿠폰발행갯수를 2배로 난수를 만들어 최종 return select 쿼리에 limit로 개수를 뽑아내는 방식을 이용하였는데 쿠폰번호가 쌓이게 되면 중복을 피할 수 없는 구조였다.
이에 loop 문을 이용해 검증 후 임시테이블에 담아둘 수 있도록 했다.
기존 Function
CREATE OR REPLACE FUNCTION ming.fn_coupon_no_generator(as_cnt integer)
RETURNS TABLE(coupon_no text)
LANGUAGE sql
AS $function$
select x1.coupon_no
from (
select trim(to_char(random() * 10000000000000000, '0000000000000000')) as coupon_no
from generate_series(1, as_cnt * 2)
except
select coupon_no as coupon_no
from ming.coupon_table
where coupon_no is not null
) x1
limit as_cnt
$function$
;
최종 쿠폰생성 Function
CREATE OR REPLACE FUNCTION MING.FN_COUPON_NO_GENERATOR(P_ORGANIZATION_CODE CHARACTER VARYING, P_CNT INTEGER)
RETURNS TABLE(COUPON_NO CHARACTER VARYING)
LANGUAGE PLPGSQL
AS $FUNCTION$
/* 변수 정의 */
DECLARE
V_ORGANIZATION_CODE VARCHAR(4) := COALESCE(P_ORGANIZATION_CODE, '5555'); --조직코드 기본값
V_RANDOM_NO VARCHAR(12) := ''; --쿠폰번호의 랜덤 12자리
V_COUPON_CNT INTEGER := 0; --만들어진 쿠폰 갯수
BEGIN
/* 임시 테이블 생성 */
DROP TABLE IF EXISTS TEMP_COUPON_TABLE;
CREATE TEMP TABLE TEMP_COUPON_TABLE(
COUPON_NO VARCHAR(16)
);
/* 랜덤 번호 생성 후 INSERT */
LOOP
INSERT INTO TEMP_COUPON_TABLE
SELECT X1.COUPON_NO
FROM (
SELECT CONCAT(V_ORGANIZATION_CODE, UPPER(SUBSTRING(MD5(RANDOM()::VARCHAR),1,12))) AS COUPON_NO
EXCEPT
SELECT T.COUPON_NO AS COUPON_NO
FROM MING.COUPON_TABLE T
WHERE T.COUPON_NO IS NOT NULL
AND T.COUPON_NO != ''
) X1;
V_COUPON_CNT = V_COUPON_CNT + 1;
EXIT WHEN V_COUPON_CNT = P_CNT; --최종 카운트에 도달하면 반복문 종료
END LOOP;
RETURN QUERY SELECT X.COUPON_NO FROM TEMP_COUPON_TABLE X LIMIT P_CNT;
END;
$FUNCTION$
;
Alias를 잘 먹여야 한다.. function 유효성검사가 너무 예민하다..
'Database' 카테고리의 다른 글
[MSSQL & SQL Server] Dirty read, WITH (NOLOCK) (0) | 2022.06.09 |
---|---|
[PostgreSQL] 유저 생성, 권한 주기 (0) | 2022.01.05 |
[PostgreSQL] ROW_NUMBER() OVER PARTITION BY를 이용한 다중컬럼 그룹핑 조회 (0) | 2021.11.23 |
[PostgreSQL] count filter를 이용한 여러건 동시추출 (0) | 2021.11.01 |
[PostgreSQL] DB내에 개행과 작은따옴표(') 사용 (0) | 2021.08.24 |