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 |
---|