목차
본문으로 바로가기

[ Redshift ] Oracle to Redshift SQL 변환 가이드

category Cloud/AWS 2025. 5. 16. 23:33

Oracle to Redshift SQL 변환 실무 가이드

이 문서는 Oracle SQL을 Amazon Redshift로 마이그레이션할 때, 필수적으로 고려해야 하는 주요 기능과 변환 방법을 우선순위별로 명확하게 정리한 실무 가이드입니다.

1. 변환 전략 요약: 우선순위별 기능 정리표

1순위 (핵심 변환 필요 항목)

카테고리 항목 및 기능 예시 변환 방식/비고
기본 SQL 함수 NVL, DECODE, SUBSTR, LTRIM, GREATEST, TO_DATE, ADD_MONTHS Redshift 동일 함수 또는 CASE/COALESCE로 변환
날짜 계산 SYSDATE, SYSTIMESTAMP, DATEDIFF, DATEADD, TRUNC, ROUND(date) 대부분 지원. ROUND(date)는 로직으로 대체 필요
윈도우 함수 RANK, DENSE_RANK, ROW_NUMBER, NTILE, PERCENT_RANK, FIRST_VALUE 문법 동일. 단, FRAME 절(ROWS BETWEEN) 주의 필요
조건 분기 처리 CASE, DECODE CASE 로 일괄 변환. 중첩 DECODE는 CASE 중첩 또는 리팩터링 필요
업무일/공휴일 계산 base_date + N (업무일), 공휴일 제외 캘린더 RECURSIVE CTE + 공휴일 테이블 방식 구현 필요

2순위 (구조 변경 또는 로직 분리 필요 항목)

카테고리 항목 및 기능 예시 변환 방식/비고
데이터 타입 CLOB, RAW, %ROWTYPE, VARCHAR2, NUMBER(p,s) VARCHAR(65535), DECIMAL, 명시적 타입 변환 필요
시퀀스 및 ID 생성 SEQUENCE.NEXTVAL, CURRVAL, SERIAL, BIGSERIAL IDENTITY, GENERATED AS IDENTITY 사용
MERGE MERGE INTO ... USING ... CTE 기반 UPSERT or DELETE + INSERT 구조로 재작성
CONNECT BY / 계층쿼리 CONNECT BY, START WITH, PRIOR RECURSIVE CTE 변환 필요

3순위 (미지원이거나 재설계 필요 항목)

카테고리 항목 및 기능 예시 변환 방식/비고
PL/SQL 문법 BEGIN ... END, EXCEPTION, CURSOR, LOOP, DBMS_OUTPUT.PUT_LINE Redshift 미지원. 외부 애플리케이션 로직 또는 Python/ETL 처리 필요
사용자 정의 타입 %ROWTYPE, OBJECT, RECORD, 사용자 정의 TYPE Redshift 미지원. 컬럼 수동 정의 필요
PostgreSQL 특화 함수 STRING_AGG, ARRAY_AGG, FORMAT, GENERATE_SERIES(), WIDTH_BUCKET() 대부분 미지원. 유사 기능은 사용자 정의 또는 CTE/로직 대체
트리거/패키지 등 TRIGGER, PACKAGE, PACKAGE BODY, RULE, EXCEPTION WHEN OTHERS 전면 재설계 필요. 애플리케이션 로직 이관 필요

2. 핵심 SQL 함수 변환 (1순위)

항목 Oracle Redshift 설명
NULL 처리 NVL(col, 'X') COALESCE(col, 'X') 다중 NULL 처리도 동일
조건 분기 DECODE(col, 'A', 'X') CASE WHEN col = 'A' THEN 'X' ELSE ... DECODE는 CASE로 전환
문자열 함수 SUBSTR, LTRIM, INSTR SUBSTRING, LTRIM, POSITION 유사함
날짜 함수 SYSDATE, ADD_MONTHS CURRENT_DATE, ADD_MONTHS 거의 동일
윈도우 함수 RANK, ROW_NUMBER 동일 ROWS BETWEEN 주의

변환이 필요 없는 함수

다음 함수들은 Oracle과 Redshift에서 동일하게 사용 가능합니다.

함수 유형 함수 목록
숫자 함수 ABS, CEIL, FLOOR, MOD, ROUND, TRUNC
문자 함수 LENGTH, LOWER, UPPER, TRIM, LTRIM, RTRIM
날짜/시간 함수 ADD_MONTHS, MONTHS_BETWEEN
변환 함수 TO_CHAR, TO_DATE, CAST
집계 함수 COUNT, SUM, AVG, MIN, MAX, LISTAGG
윈도우 함수 ROW_NUMBER, RANK, DENSE_RANK, LAG, LEAD
조건 함수 CASE

변환이 필요한 함수

Oracle에서 Redshift로 변환이 필요한 함수입니다.

Oracle 함수 Redshift 함수 설명    
SYSDATE GETDATE() 또는 CURRENT_DATE 현재 날짜와 시간 반환 함수    
SUBSTR SUBSTRING 문자열의 일부를 추출하는 함수    
NVL COALESCE NULL 값을 지정된 값으로 대체하는 함수    
DECODE CASE 문으로 변환 필요 조건별 값 반환 함수    
CONCAT CONCAT 또는 `   ` 연산자 문자열 연결
INSTR POSITION 문자열 내 특정 문자열 위치 반환    
LPAD/RPAD LPAD/RPAD 지정 길이로 문자열에 패딩 추가    
REGEXP_SUBSTR REGEXP_SUBSTR 정규 표현식을 사용한 문자열 추출    
TO_TIMESTAMP TO_TIMESTAMP 문자열을 타임스탬프로 변환    
TRUNC(날짜) DATE_TRUNC 날짜를 지정 단위로 자름    
ROUND(날짜) DATE_TRUNC 또는 사용자 정의 함수 날짜를 지정 단위로 반올림 (Redshift에 직접 대응 없음)    
EXTRACT EXTRACT 날짜/시간의 특정 부분 추출    
SYSTIMESTAMP CURRENT_TIMESTAMP 현재 타임스탬프 반환    
TO_YMINTERVAL/TO_DSINTERVAL 직접적인 대응 없음 연월 또는 일시 간격 변환 (대응 없음)    
NUMTODSINTERVAL/NUMTOYMINTERVAL 직접적인 대응 없음 숫자를 일시 또는 연월 간격 변환 (대응 없음)    
WIDTH_BUCKET 직접적인 대응 없음 히스토그램 버킷 계산 (대응 없음)    

복잡한 변환 예제 (초보자용 설명 포함)

NTILE → 동일 문법

-- Oracle / Redshift 동일
SELECT emp_id,
       NTILE(4) OVER (ORDER BY salary) AS quartile
FROM employees;

📘 설명: NTILE은 데이터를 지정된 개수의 구간으로 나누어 그룹을 부여합니다. Oracle과 Redshift 모두 동일한 문법을 사용합니다.


PERCENT_RANK → 동일 문법

-- Oracle / Redshift 동일
SELECT emp_id,
       PERCENT_RANK() OVER (ORDER BY salary) AS pct_rank
FROM employees;

📘 설명: PERCENT_RANK는 상대적 백분율 순위를 계산합니다. 순위 - 1 / (전체 행 - 1) 공식 기반이며, Oracle/Redshift 동일하게 지원됩니다.


FIRST_VALUE / LAST_VALUE → 동일 문법 + FRAME 절 주의

-- Oracle
SELECT FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY hire_date) FROM employees;

-- Redshift
SELECT FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY hire_date
                                 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM employees;

📘 설명: FIRST_VALUE, LAST_VALUE는 윈도우 내 첫/마지막 값을 구하는 함수입니다. Redshift에서는 ROWS BETWEEN 절이 명시되지 않으면 결과가 예상과 다를 수 있으므로 반드시 지정하는 것이 좋습니다.


SUBSTR 중첩 → 동일 문법

-- Oracle
SELECT SUBSTR(SUBSTR(name, 2), 1, 5) FROM users;

-- Redshift
SELECT SUBSTRING(SUBSTRING(name, 2), 1, 5) FROM users;

📘 설명: 중첩된 SUBSTR 함수는 Redshift에서도 SUBSTRING 함수로 동일하게 중첩 사용 가능합니다.


중첩 NVL → COALESCE 변환

-- Oracle
SELECT NVL(NVL(col1, col2), col3) AS nested_nvl FROM employees;

-- Redshift
SELECT COALESCE(col1, col2, col3) AS nested_nvl FROM employees;

📘 설명: 중첩된 NVL은 Redshift에서 COALESCE를 통해 단일 함수로 간단히 표현할 수 있습니다.


중첩 DECODE → 중첩 CASE

-- Oracle
SELECT DECODE(DECODE(status, 'A', 'Active', 'I', 'Inactive'), 'Active', 1, 0) AS decoded_status FROM users;

-- Redshift
SELECT CASE
         WHEN status = 'A' THEN 1
         WHEN status = 'I' THEN 0
         ELSE 0
       END AS decoded_status FROM users;

📘 설명: 중첩 DECODE는 Redshift의 CASE 문을 중첩하거나 병합하여 논리를 구성해야 합니다. 가독성을 위해 간단한 CASE로 재작성하는 것을 추천합니다.


RAW → VARCHAR 또는 BYTEA (Redshift 미지원)

-- Oracle
CREATE TABLE files (
  id NUMBER,
  data RAW(2000)
);

-- Redshift (대체)
CREATE TABLE files (
  id INT,
  data VARCHAR(MAX) -- 또는 Base64 인코딩 사용
);

📘 설명: Oracle의 RAW는 이진 데이터를 저장하는 타입입니다. Redshift는 RAW 타입을 지원하지 않으며, 일반적으로 VARCHAR에 Base64로 인코딩하여 저장하거나 외부 스토리지(S3 등)에 저장하고 참조하는 방식을 사용합니다.


DENSE_RANK → 동일 문법

-- Oracle / Redshift 동일
SELECT *,
       DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dr
FROM employees;

📘 설명: DENSE_RANK는 동일한 순위 값을 가진 행이 있어도 건너뛰지 않고 연속된 순위를 부여합니다. Oracle과 Redshift 모두 동일한 문법을 사용합니다.


CLOB → VARCHAR 또는 SUPER

-- Oracle
CREATE TABLE doc_table (
  doc_id NUMBER,
  doc_text CLOB
);

-- Redshift
CREATE TABLE doc_table (
  doc_id INT,
  doc_text VARCHAR(MAX) -- 또는 SUPER 타입
);

📘 설명: Oracle의 CLOB는 대용량 문자 데이터를 저장하는 데이터 타입입니다. Redshift에서는 VARCHAR(MAX)로 충분히 대응되며, JSON 구조가 필요한 경우 SUPER 타입을 사용할 수 있습니다.


GREATEST → CASE 또는 UDF

-- Oracle
SELECT GREATEST(100, 200, 150) FROM dual; -- 결과: 200

-- Redshift
SELECT GREATEST(100, 200, 150);

📘 설명: GREATEST는 인자 중 가장 큰 값을 반환합니다. Redshift에서도 동일한 GREATEST 함수가 지원됩니다. 단, 일부 환경에서는 UDF로 정의해야 할 수 있습니다.


ROW_NUMBER → 동일 문법

-- Oracle / Redshift 동일
SELECT *,
       ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
FROM employees;

📘 설명: ROW_NUMBER는 파티션별 정렬 기준에 따라 고유 순번을 부여합니다. Oracle과 Redshift 모두 동일한 문법으로 사용 가능합니다.


SEQUENCE.NEXTVAL → IDENTITY / GENERATED BY DEFAULT AS IDENTITY

-- Oracle
CREATE SEQUENCE seq1 START WITH 1;
SELECT seq1.NEXTVAL FROM dual;

-- Redshift
-- 테이블 생성 시 IDENTITY 설정
CREATE TABLE example (
  id INT IDENTITY(1,1),
  name VARCHAR(100)
);

📘 설명: Oracle의 시퀀스는 NEXTVAL로 값을 증가시키지만 Redshift는 IDENTITY 속성으로 자동 증가 컬럼을 생성합니다. 별도 SEQUENCE 객체는 지원하지 않습니다.


DECODE → CASE

-- Oracle (단순 DECODE)
SELECT DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown') FROM dual;

-- Redshift
SELECT CASE
         WHEN status = 'A' THEN 'Active'
         WHEN status = 'I' THEN 'Inactive'
         ELSE 'Unknown'
       END;

📘 설명: DECODE는 간단한 조건 분기 함수입니다. Redshift에서는 이를 CASE 문으로 바꿔야 하며, 조건 → THEN 결과 순서로 작성하면 됩니다.

-- Oracle (다중 DECODE)
SELECT DECODE(type,
              'A', 'Apple',
              'B', 'Banana',
              'C', 'Cherry',
              'D', 'Date',
              'Unknown')
FROM fruits;

-- RedshiftGREATEST
SELECT CASE
         WHEN type = 'A' THEN 'Apple'
         WHEN type = 'B' THEN 'Banana'
         WHEN type = 'C' THEN 'Cherry'
         WHEN type = 'D' THEN 'Date'
         ELSE 'Unknown'
       END
FROM fruits;

📘 설명: DECODE는 인자 순서가 "조건, 결과, 조건, 결과..." 형태입니다. 이를 CASE 문으로 바꾸려면 각 조건-결과 쌍을 WHEN-THEN으로 순서대로 나열한 뒤 ELSE 구문으로 마무리하면 됩니다.

-- Oracle
SELECT DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown') FROM dual;

-- Redshift
SELECT CASE
         WHEN status = 'A' THEN 'Active'
         WHEN status = 'I' THEN 'Inactive'
         ELSE 'Unknown'
       END;

📘 설명: DECODE는 간단한 조건 분기 함수입니다. Redshift에서는 이를 CASE 문으로 바꿔야 하며, 조건 → THEN 결과 순서로 작성하면 됩니다.


NVL → COALESCE

-- Oracle (단일 NVL)
SELECT NVL(comm, 0) FROM emp;

-- Redshift
SELECT COALESCE(comm, 0) FROM emp;

📘 설명: NVL은 NULL 값을 다른 값으로 바꾸는 함수입니다. Redshift에서는 COALESCE가 그 역할을 하며, 첫 번째 인자가 NULL이면 두 번째 값을 반환합니다.

-- Oracle (다중 NVL)
SELECT NVL(NVL(phone, mobile), 'N/A') FROM contacts;

-- Redshift (다중 COALESCE)
SELECT COALESCE(phone, mobile, 'N/A') FROM contacts;

📘 설명: 여러 필드 중 NULL이 아닌 첫 번째 값을 선택하려면 Oracle에서는 중첩된 NVL을 사용하지만, Redshift에서는 COALESCE에 인자를 여러 개 나열하면 됩니다.

-- Oracle
SELECT NVL(comm, 0) FROM emp;

-- Redshift
SELECT COALESCE(comm, 0) FROM emp;

📘 설명: NVL은 NULL 값을 다른 값으로 바꾸는 함수입니다. Redshift에서는 COALESCE가 그 역할을 하며, 첫 번째 인자가 NULL이면 두 번째 값을 반환합니다.


CONNECT BY / START WITH / PRIOR → 재귀 CTE

-- Oracle: 1~70 숫자 생성
SELECT LEVEL AS n FROM dual CONNECT BY LEVEL <= 70;

-- Redshift: RECURSIVE CTE 사용
WITH RECURSIVE numbers AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM numbers WHERE n < 70
)
SELECT * FROM numbers;

📘 설명: Oracle의 CONNECT BY 구문은 계층 구조나 반복 쿼리를 쉽게 만듭니다. Redshift는 WITH RECURSIVE를 사용해 동일한 로직을 구현할 수 있습니다. 초기 값과 반복 조건을 주의 깊게 설정하세요.


MERGE → UPSERT 대체

-- Oracle MERGE 문
MERGE INTO target t
USING source s
ON (t.id = s.id)
WHEN MATCHED THEN
  UPDATE SET t.name = s.name
WHEN NOT MATCHED THEN
  INSERT (id, name) VALUES (s.id, s.name);

-- Redshift 방식 1: DELETE + INSERT
DELETE FROM target
WHERE id IN (SELECT id FROM staging);

INSERT INTO target
SELECT * FROM staging;

-- Redshift 방식 2: CTE 기반 UPSERT
WITH updates AS (
  SELECT s.*
  FROM source s
  JOIN target t ON s.id = t.id
),
insertions AS (
  SELECT * FROM source
  WHERE id NOT IN (SELECT id FROM target)
)
-- 실행: 별도로 적용 필요
-- 1. UPDATE target SET ... FROM updates u WHERE target.id = u.id
-- 2. INSERT INTO target SELECT * FROM insertions;

📘 설명: Oracle의 MERGE는 조건에 따라 UPDATE 또는 INSERT를 수행합니다. Redshift에서는 MERGE가 지원되지 않기 때문에 DELETE + INSERT 또는 CTE를 이용한 UPSERT 방식으로 나누어 처리해야 합니다.

-- Oracle
MERGE INTO target t
USING source s
ON (t.id = s.id)
WHEN MATCHED THEN
  UPDATE SET t.name = s.name
WHEN NOT MATCHED THEN
  INSERT (id, name) VALUES (s.id, s.name);

-- Redshift
-- Step 1: DELETE FROM target WHERE id IN (SELECT id FROM staging);
-- Step 2: INSERT INTO target SELECT * FROM staging;

📘 설명: Redshift는 MERGE 문을 지원하지 않기 때문에 staging 테이블을 만들어 DELETE 후 INSERT하는 방식으로 UPSERT를 구현합니다.


EXCEPTION → 예외 처리 미지원

-- Oracle
BEGIN
  ...
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
END;

-- Redshift
-- 예외 처리는 Redshift에서 지원되지 않으며 외부 앱 또는 ETL 도구에서 처리해야 합니다.

📘 설명: Redshift는 PL/pgSQL 예외 처리 블록(EXCEPTION)을 지원하지 않으므로 오류 처리는 외부 로직으로 구현해야 합니다.


REVERSE → 사용자 정의 필요

-- Oracle
SELECT REVERSE('hello') FROM dual;

-- Redshift
-- 예: SELECT REVERSE_STRING('hello'); -- 사용자 정의 함수 필요

📘 설명: Redshift에는 문자열을 뒤집는 REVERSE 함수가 없기 때문에 Python UDF나 문자열 함수 조합을 통해 직접 구현해야 합니다.


ROWTYPE → 구조체 정의 필요

-- Oracle
DECLARE
  emp_record employees%ROWTYPE;

-- Redshift
-- 사용 불가. 모든 컬럼을 개별적으로 선언해야 합니다.

📘 설명: ROWTYPE은 테이블 구조를 그대로 참조해 레코드를 선언할 수 있게 해줍니다. Redshift에서는 이 기능이 없어 모든 필드를 직접 선언해야 합니다.


🎯 조건 함수 (CASE) 예제 추가

단순 CASE 문 예제

SELECT employee_id,
       CASE status
         WHEN 'A' THEN 'Active'
         WHEN 'I' THEN 'Inactive'
         ELSE 'Unknown'
       END AS status_desc
FROM employees;

복합 조건 CASE 문 예제

SELECT employee_id,
       salary,
       CASE 
         WHEN salary >= 10000 THEN 'A'
         WHEN salary >= 7000 THEN 'B'
         WHEN salary >= 5000 THEN 'C'
         ELSE 'D'
       END AS grade
FROM employees;

다중 조건 포함 CASE 예제

SELECT employee_id,
       department_id,
       salary,
       CASE
         WHEN department_id = 10 AND salary >= 8000 THEN 'Senior IT'
         WHEN department_id = 10 AND salary < 8000 THEN 'Junior IT'
         WHEN department_id = 20 THEN 'HR'
         WHEN department_id = 30 THEN 'Sales'
         ELSE 'Others'
       END AS role_category
FROM employees;

3. 데이터 구조 및 제어 흐름 (2순위)

항목 Oracle Redshift 변환 방식
시퀀스 SEQUENCE.NEXTVAL IDENTITY, 수동 증가 CREATE TABLE 시 정의
MERGE MERGE INTO ... DELETE + INSERT, CTE UPSERT MERGE 미지원
계층 쿼리 CONNECT BY RECURSIVE CTE WITH RECURSIVE 사용
%ROWTYPE 테이블 기반 타입 참조 미지원 컬럼 수동 정의 필요

4. 지원되지 않거나 외부 처리 필요한 항목 (3순위)

항목 예시 대응 방안
PL/SQL 블록 BEGIN...END, EXCEPTION ETL, Python, DBT로 처리
사용자 정의 타입 %ROWTYPE, RECORD, OBJECT 컬럼 수동 지정
트리거/패키지 TRIGGER, PACKAGE 이벤트 기반 외부 처리
PostgreSQL 특화 함수 STRING_AGG, ARRAY_AGG, GENERATE_SERIES() RECURSIVE CTE, 사용자 정의 함수

PL/SQL 구조 및 프로그래밍 요소

Oracle PL/SQL 기능 Redshift에서의 상태 설명
EXCEPTION 블록 ❌ 미지원 오류 핸들링 불가. 외부 애플리케이션 로직으로 대체 필요
PACKAGE / PACKAGE BODY ❌ 미지원 Redshift는 패키지 개념 없음. UDF 단위로 나누거나 외부 처리 필요
PROCEDURE / FUNCTION (PL/SQL) 제한적 지원 Redshift는 SQL 기반 UDF만 지원. 복잡한 로직은 Lambda/UDF로 이관 고려
CURSOR (FOR LOOP 등) ❌ 미지원 Redshift는 커서 기반 반복/제어문을 지원하지 않음
Autonomous Transaction ❌ 미지원 독립 트랜잭션 불가. 로깅 처리 구조 변경 필요
DBMS_OUTPUT.PUT_LINE ❌ 미지원 출력 함수 없음. 외부 로그 또는 SELECT 방식으로 대체
USER-DEFINED OBJECT TYPES ❌ 미지원 Redshift는 사용자 정의 타입(STRUCT 등)을 지원하지 않음
ROWTYPE ❌ 미지원 테이블 스키마 참조 변수 불가. 모든 컬럼 직접 명시해야 함

5. 데이터 타입 변환

Oracle 데이터 타입 Redshift 대응 타입 비고
VARCHAR2(n) VARCHAR(n) 최대 65535
CLOB VARCHAR(65535) SUPER 타입도 가능
NUMBER DECIMAL(18,0) 또는 BIGINT 정수/실수 구분
NUMBER(p,s) DECIMAL(p,s) 정밀도 유지
FLOAT DOUBLE PRECISION 부동소수점
DATE DATE 동일
TIMESTAMP TIMESTAMP 동일
RAW 변환 불가 – Base64 인코딩 후 VARCHAR 처리  
%ROWTYPE 변환 불가 – 수동 컬럼 나열 또는 JSON 구조 정의  

날짜/시간 타입 변환 시 주의사항 및 예제

Oracle 표현 Redshift 표현 주의사항
SYSDATE CURRENT_DATE 또는 GETDATE() SYSDATE는 날짜, GETDATE는 타임스탬프 반환
SYSTIMESTAMP CURRENT_TIMESTAMP 마이크로초 포함 전체 타임스탬프 반환
TO_DATE('2024-01-24', 'YYYY-MM-DD') TO_DATE('2024-01-24', 'YYYY-MM-DD') 동일하지만 포맷은 항상 명시 권장
TO_TIMESTAMP('2024-01-24 12:34:56', 'YYYY-MM-DD HH24:MI:SS') TO_TIMESTAMP('2024-01-24 12:34:56', 'YYYY-MM-DD HH24:MI:SS') 포맷 코드 HH24, MI, SS 동일 사용 가능
ADD_MONTHS(date_col, 3) ADD_MONTHS(date_col, 3) Oracle과 동일한 함수 지원됨
TRUNC(SYSDATE, 'MM') DATE_TRUNC('month', CURRENT_DATE) Redshift는 DATE_TRUNC 사용
ROUND(date_col, 'MONTH') 별도 구현 필요 Redshift는 ROUND로 날짜 반올림 불가, 사용자 정의 구현 필요
SYSDATE - hire_date DATEDIFF(day, hire_date, CURRENT_DATE) 날짜 차이를 일 단위로 반환
hire_date + 90 DATEADD(day, 90, hire_date) 날짜 연산은 DATEADD 함수 사용
INTERVAL '6' MONTH DATEADD(month, 6, CURRENT_DATE) INTERVAL은 DATEADD로 대체

변환 시 고려할 점:

  • Redshift는 타임존 처리를 명시적으로 하지 않으면 UTC 기준
  • 날짜 포맷 문자열이 Oracle보다 엄격하므로 반드시 명시적 포맷 지정
  • ROUND(date, 'MONTH') 같은 날짜 반올림은 사용자 정의 로직 필요
  • 날짜 연산 시 INTERVAL 사용은 Redshift에서도 가능하지만 일부 연/월 처리 제한 있음

📘 참고: 일부 Oracle 전용 타입(CURSOR, OBJECT, RECORD)은 구조적으로 Redshift에서 대체가 어렵기 때문에, ETL 파이프라인 또는 애플리케이션 레벨로 분리하는 것이 바람직합니다.

다음 항목은 Redshift에서 지원되지 않거나 대체가 까다로운 기능입니다. 가능하면 아키텍처 차원에서 재설계 또는 외부 도구 연계를 고려해야 합니다.

Oracle 기능 Redshift에서의 상태 설명
EXCEPTION 블록 미지원 Redshift는 PL/pgSQL의 EXCEPTION 블록을 지원하지 않음. 오류 처리는 외부에서 수행 필요
Autonomous Transaction 미지원 Redshift는 독립 트랜잭션 구조를 지원하지 않음
Package / Package Body 미지원 Redshift는 패키지 개념이 없음. UDF 또는 외부 모듈로 재설계 필요
Cursor FOR UPDATE 부분 지원 불가 Redshift는 커서를 통한 행 잠금이 불가능함. 동시성 제어 구조 필요
DBMS_OUTPUT.PUT_LINE 미지원 Redshift에는 디버깅 출력 기능이 없어 로깅/디버깅은 외부 처리 필요
USER-DEFINED OBJECT TYPES 미지원 Redshift는 사용자 정의 객체 타입(STRUCT 등)을 지원하지 않음
ROWTYPE 미지원 테이블 구조 기반 변수 선언 불가. 필드를 직접 정의해야 함
-- Oracle 예시
SELECT SYSDATE, SYSTIMESTAMP FROM dual;
SELECT TO_DATE('2024-01-24', 'YYYY-MM-DD') FROM dual;
SELECT ADD_MONTHS(SYSDATE, 6) FROM dual;
SELECT TRUNC(SYSDATE, 'YEAR') FROM dual;
SELECT hire_date + 90 FROM emp;
SELECT SYSDATE - hire_date FROM emp;

-- Redshift 예시
SELECT CURRENT_DATE, CURRENT_TIMESTAMP;
SELECT TO_DATE('2024-01-24', 'YYYY-MM-DD');
SELECT ADD_MONTHS(CURRENT_DATE, 6);
SELECT DATE_TRUNC('year', CURRENT_DATE);
SELECT DATEADD(day, 90, hire_date) FROM emp;
SELECT DATEDIFF(day, hire_date, CURRENT_DATE) FROM emp;

📌 금융권 활용 예시 (이자 계산, 만기일 등)

-- 대출 만기일 계산 (6개월 후)
SELECT ADD_MONTHS(loan_date, 6) AS maturity_date FROM loans;

-- 남은 만기일 계산
SELECT DATEDIFF(day, CURRENT_DATE, maturity_date) AS days_remaining FROM loans;

-- 기준일 기준 3일 후 계산
SELECT DATEADD(day, 3, base_date) FROM schedule;

📌 금융권 특화: 업무일 계산 및 공휴일 제외 로직

-- 공휴일 테이블을 이용한 업무일 계산
-- 예: 기준일 + N 업무일 계산
WITH calendar AS (
  SELECT date::date AS work_day
  FROM generate_series('2024-01-01', '2024-12-31', interval '1 day')
  WHERE EXTRACT(DOW FROM date) NOT IN (0, 6) -- 주말 제외
    AND date NOT IN (SELECT holiday_date FROM holiday_table) -- 공휴일 제외
),
ordered AS (
  SELECT work_day,
         ROW_NUMBER() OVER (ORDER BY work_day) AS work_seq
  FROM calendar
),
base AS (
  SELECT CURRENT_DATE AS base_day
),
current_idx AS (
  SELECT o.work_seq FROM ordered o JOIN base b ON o.work_day >= b.base_day ORDER BY o.work_day LIMIT 1
)
SELECT o.work_day AS n_business_day
FROM ordered o, current_idx c
WHERE o.work_seq = c.work_seq + 3;

설명:

  • holiday_table에는 제외할 공휴일 리스트를 미리 관리합니다.
  • generate_series는 Redshift에서는 직접 지원되지 않기 때문에 사전 생성된 캘린더 테이블을 활용하거나 RECURSIVE CTE로 대체 필요합니다.
-- RECURSIVE CTE 방식 (generate_series 대체)
WITH RECURSIVE calendar(date_val) AS (
  SELECT CAST('2024-01-01' AS DATE)
  UNION ALL
  SELECT date_val + 1 FROM calendar WHERE date_val < '2024-12-31'
)
SELECT *
FROM calendar
WHERE EXTRACT(DOW FROM date_val) NOT IN (0, 6)
  AND date_val NOT IN (SELECT holiday_date FROM holiday_table);

활용 예:

  • 업무일 기준 만기일 계산
  • 예치 기간 산정
  • 신용카드 청구일 산정 (공휴일 보정)
  • 펀드 자동이체일 조정
-- Oracle: 대출 만기일 계산 (6개월 후)
SELECT ADD_MONTHS(loan_date, 6) AS maturity_date FROM loans;

-- Redshift:
SELECT ADD_MONTHS(loan_date, 6) AS maturity_date FROM loans;

-- Oracle: 남은 만기일 계산
SELECT maturity_date - SYSDATE AS days_remaining FROM loans;

-- Redshift:
SELECT DATEDIFF(day, CURRENT_DATE, maturity_date) AS days_remaining FROM loans;

-- Oracle: 기준일 기준 3일 후 업무일 계산 예시 (로직 필요)
SELECT base_date + 3 FROM schedule;

-- Redshift:
SELECT DATEADD(day, 3, base_date) FROM schedule;

변환 시 고려할 점:

  • Redshift는 날짜 차이 계산 시 DATEDIFF(unit, start, end)을 사용하며 단위 명시가 필요합니다.
  • 날짜 더하기는 DATEADD(unit, value, base_date)로 표현합니다.
  • INTERVAL 구문은 Redshift에서는 직접 사용 불가하며 DATEADD로 대체해야 합니다.
  • 금융권에서는 이자 계산, 만기일, 업무일 계산 등 날짜 정확성이 중요하므로 변환 후 테스트 필수입니다.

날짜 및 시간 관련 데이터 타입은 Oracle과 Redshift 간에 기본적으로 유사하지만, 다음과 같은 차이점을 반드시 고려해야 합니다.

6. 변환 불가능 또는 비권장 기능

다음 항목은 Redshift에서 지원되지 않거나 PostgreSQL과의 차이로 인해 대체가 어렵거나 동작이 다르게 구현되는 기능들입니다.

PL/SQL 및 Oracle 독자 기능

Oracle PL/SQL 기능 Redshift에서의 상태 설명
EXCEPTION 블록 미지원 오류 핸들링 불가. 외부 애플리케이션 로직으로 대체 필요
PACKAGE / PACKAGE BODY 미지원 Redshift는 패키지 개념 없음. UDF 단위로 나누거나 외부 처리 필요
PROCEDURE / FUNCTION (PL/SQL) 제한적 지원 Redshift는 SQL 기반 UDF만 지원. 복잡한 로직은 Lambda/UDF로 이관 고려
CURSOR (FOR LOOP 등) 미지원 Redshift는 커서 기반 반복/제어문을 지원하지 않음
Autonomous Transaction 미지원 독립 트랜잭션 불가. 로깅 처리 구조 변경 필요
DBMS_OUTPUT.PUT_LINE 미지원 출력 함수 없음. 외부 로그 또는 SELECT 방식으로 대체
USER-DEFINED OBJECT TYPES 미지원 사용자 정의 타입(STRUCT 등)을 지원하지 않음
ROWTYPE 미지원 테이블 스키마 참조 변수 불가. 모든 컬럼 직접 명시해야 함

PostgreSQL과 Redshift의 차이 및 미지원 기능

PostgreSQL 함수/기능 Redshift 상태 비고
STRING_AGG, ARRAY_AGG, XMLAGG 미지원 LISTAGG 등으로 대체하거나 불가
ARRAY 관련 함수 전체 미지원 Redshift는 배열 타입을 지원하지 않음
CLOCK_TIMESTAMP, TRANSACTION_TIMESTAMP 미지원 GETDATE 또는 CURRENT_TIMESTAMP 사용
WIDTH_BUCKET 미지원 사용자 정의 함수로 구현 필요
OVERLAY, FORMAT, ENCODE 미지원 문자열 조작은 다른 방식 사용 필요
BIT_LENGTH, CHAR_LENGTH 일부 제한적 결과 및 처리 방식이 다를 수 있음
IS DISTINCT FROM 미지원 COALESCE + 비교 조합으로 우회 필요
GENERATE_SERIES 미지원 RECURSIVE CTE로 유사 기능 구현 가능
NULLS FIRST/LAST 미지원 ORDER BY 절에서 명시 불가
SERIAL, BIGSERIAL 미지원 IDENTITY 또는 SEQUENCE 사용
TRIGGER, RULE, PARTITION 미지원 구조 자체 미지원, ETL 또는 앱 레벨 처리 필요
CHECK, UNIQUE, FOREIGN KEY 명세용만 존재 실제 제약 조건은 강제되지 않음

7. 실무 적용 시 주의사항

  • 변환 자동화 도구를 사용할 때 변환 누락이나 부정확한 변환에 대한 추가 검증이 필요합니다.
  • Oracle의 미지원 기능을 그대로 사용하지 말고, Redshift의 특성을 충분히 이해한 후 구조를 재설계하세요.
  • 데이터 무결성 및 성능 최적화를 위해 변환된 쿼리의 성능 테스트를 반드시 수행하세요.
  • 날짜와 시간 처리 시 타임존 차이를 고려하여 결과를 검증하세요.
  • 복잡한 변환의 경우 충분한 주석과 문서화를 통해 유지보수를 용이하게 하세요.

8. 실무 적용 전략

  • 변환 자동화 도구 활용 (SQL Parser 등)
  • 필수 변환 항목 중심으로 마이그레이션 계획
  • 테스트/검증 자동화 (테스트 케이스 작성)

9. 참고 자료

'Cloud > AWS' 카테고리의 다른 글

[Management Tool] CLI를 활용한 S3 구성 가이드  (0) 2025.05.25