Server/- PostgreSQL

PostgreSQL Query

즐겁게 하하하 2022. 4. 26. 16:55
728x90

형식크기범위별칭

smallint 2 바이트 -32768에서 +32767 int2
integer 4 바이트 -2147483648에서 +2147483647 int, int4
bigint 8 바이트 -9223372036854775808에서 +9223372036854775807 int8

 

 ===null 대체===
 Oracle      ==> nvl()
 SQL Server  ==> isnull()
 PostgreSQL  ==> COALESCE()

SELECT COALESCE(etc,'널입니다~')  FROM test as tp  => 널입니다~

 

Oracle LPAD와 동일 기능
원하는 문자열로 설정된 byte만큼 왼쪽으로 채움
SELECT LPAD(COALESCE(etc,'1'),10,'0') FROM test as tp  => 0000000001

Oracle RPAD와 동일 기능
원하는 문자열로 설정된 byte만큼 오른쪽으로 채움

 

유니크한 ID 만들기
SELECT LPAD(  CAST(CAST(COALESCE(MAX(etc),'0') AS NUMERIC)+1 AS CHARACTER VARYING),10,'0')
FROM test_point as tp

 

문자열을 구분자로 자를 경우 ===> split_part ===> split_part(date::TEXT, '-', 1)::SMALLINT 
문자열을 합칠 경우 ===> concat ===> concat(first_name,'-',last_name) 

1. 코드 분석

<insert id="setInsertCu">
INSERT INTO tn_cust
	(cu_id, tr_id, cu_nm)
VALUES(
	(SELECT 'CKD'||lpad((split_part(COALESCE(max(cu_id),'CKD000000'), 'CKD',2)::int+1)::text,6,'0') FROM tn_cu)
	, #{trdr_id}
	, NOW()
)
</insert>
_________________________________________
COALESCE(max(cu_id),'CKD000000') 
  =>  null 인 경우 대체
  
split_part( '55CKD000' , 'CKD',2)::int+1 
  => 문자열을 CKD 문자 기준으로 자르고 + 1 (위치 1부터 시작)
  => index1 : 55 , index2 : 0(int)
  
split_part( 'CKD000' , 'CKD',2)::int+1 
  => 문자열을 CKD 문자 기준으로 자르고 + 1 (위치 1부터 시작)
  => index1 : 공백 , index2 : 0(int)
  
lpad('1',6,'0') => 0을 문자열로 설정된 6byte만큼 왼쪽으로 채움 000001(0을5개왼쪽으로)

'CKD'|| => 문자열 'CKD'를 붙임

 


2. 코드분석

재귀적 쿼리인데 이는 보통 테이블 데이터가 계층형일때 많이 사용된다.

WITH RECURSIVE 구문을 통해 쿼리가 반복되며,

반복된 결과를 parent query 영역에서 FROM 절로 가져와 사용하는 구조로

UNION 다음에 사용되는 recursive query

즉, 재귀쿼리문에서는 보통 where 조건을 통해 반복이 멈추도록 제한을 둔다

WITH RECURSIVE recursive_name [(column1, ...)] AS (
   -- initial query (처음 호출하는 쿼리)
   -- non-recursive query
   SELECT [(column1, ...)]
   
   UNION [ALL]
   
   -- recursive query (반복 쿼리)
   SELECT [(column1, ...)] FROM recursive_name [WHERE]
)
-- parent query
SELECT * FROM recursive_name

 

예시1

WITH RECURSIVE mine_record AS ( 
  SELECT 1 AS num UNION ALL SELECT num + 1 FROM mine_record WHERE num < 10 
) SELECT * FROM mine_record

예시2

WITH RECURSIVE dept_record(
   dept_sn, parent_sn, dept_name, dept_ctn, level, path, cycle
) AS( 

   -- initial query (처음 호출하는 쿼리)
   -- non-recursive query
   SELECT d.dept_sn, d.parent_sn, d.dept_name, d.dept_ctn, 0, ARRAY[d.dept_sn], false 
   FROM dept d WHERE d.parent_sn IS NULL 
      
   UNION ALL 
      
   -- recursive query (반복 쿼리)
   SELECT d.dept_sn, d.parent_sn, d.dept_name, d.dept_ctn, 
   level + 1, path || d.dept_sn, d.dept_sn = ANY(path) 
   FROM dept d, dept_record dr 
   WHERE d.parent_sn = dr.dept_sn AND NOT CYCLE 
   
) SELECT 
   dept_sn, parent_sn, dept_name, dept_ctn, level, path 
  FROM dept_record 
  ORDER BY path -- parent query

쿼리가 반복되는 부분에 dept_sn을 배열로 담은 path에 각각의 dept_sn을 추가해 계층형 쿼리가 완성됐다.

 

위 예제에서 사용되는 cycle은 성능상 추가된것인데,

path에 이미 추가된 데이터에 대해서는 더이상 검색을 수행하지 않게 중복 처리를 제한것이다. 

 

예시3 : 아래 코드를 분석해 보자

<select id="getTreeList" parameterType="java.util.Map" resultType="hashMap">
    /* "commonDAO.getTreeList */
    WITH RECURSIVE TREE_OGDP(OGDP_ID, OGDP_NM, UP_OGDP_ID, DEPTH, PATH, CYCLE) AS (
        SELECT 
            A.OGDP_ID,
            A.OGDP_NM,   
            A.UP_OGDP_ID,
            1,
            ARRAY[A.OGDP_ID::text],
            FALSE
        FROM TN_OGDP A
        WHERE UP_OGDP_ID = '#'
        UNION ALL
        SELECT 
            A.OGDP_ID,
            A.OGDP_NM,   
            A.UP_OGDP_ID,
            B.DEPTH + 1,
            ARRAY_APPEND(B.PATH, A.OGDP_ID::text),
            A.OGDP_ID = ANY(B.PATH)
        FROM TN_OGDP A, TREE_OGDP B
        WHERE A.UP_OGDP_ID = B.OGDP_ID
        AND NOT CYCLE
    )
    SELECT 
        A.OGDP_ID AS ID, A.OGDP_NM AS TEXT, A.UP_OGDP_ID AS PARENT,
        B.USER_ID, B.USER_NM, A.OGDP_ID, A.OGDP_NM, A.UP_OGDP_ID
    FROM TREE_OGDP A, TN_USER B
    WHERE A.OGDP_ID = B.OGDP_ID
    ORDER BY PATH
</select>

3. 코드분석 array_to_string

<select id="getCustIdArray" resultType="string">
    /* custDAO.getCustIdArray */ 
    SELECT
     array_to_string( 
         ARRAY(
            select cust_id from tn_cust
          )
      , ', ') AS all_cust_id
</select>

728x90