본문 바로가기
실험실/db이행

Oracle SQL을 PostgreSQL SQL로 바꿀 때 MyBatis에서 자동 치환 가능한 것 / 절대 안 되는 것 목록

by 죄니안죄니 2026. 1. 30.

MyBatis XML 기준,

Oracle SQL → PostgreSQL SQL 전환 시

  • 정규식·스크립트로 자동 치환 가능한 것
  • 절대 자동 치환하면 안 되는 것(사람이 재작성해야 하는 것)

실무 기준으로 정리한 목록.


1️⃣ 자동 치환 가능한 것 (Script / Regex로 처리 가능)

조건: 의미가 1:1로 대응되고, 결과가 달라질 여지가 거의 없는 것


✅ 1. NULL 처리 함수

Oracle  PostgreSQL  비고
NVL(a, b) COALESCE(a, b) 의미 동일
NVL2(a, b, c) CASE WHEN a IS NOT NULL THEN b ELSE c END 패턴 치환 가능

📌 주의

  • NVL 안에 서브쿼리/함수 중첩돼 있어도 대부분 안전

✅ 2. 문자열 함수 (단순형)

Oracle  PostgreSQL
SUBSTR(a, b, c) SUBSTRING(a FROM b FOR c)
LENGTH(a) LENGTH(a)
TRIM(a) TRIM(a)
UPPER / LOWER 동일

📌 권장

  • SUBSTR → SUBSTRING은 정규식 치환으로 가능
  • 단, 인자 순서 바뀌는 것만 주의

✅ 3. 날짜 계산 (단순 산술)

Oracle  PostgreSQL
SYSDATE now()
SYSDATE - 1 now() - interval '1 day'
SYSDATE + 7 now() + interval '7 days'

📌 주의

  • 컬럼 타입이 date인지 timestamp인지 확인은 필요
  • 그래도 자동 치환 대상에 포함 가능

✅ 4. DUAL 제거

-- Oracle
SELECT1FROM DUAL;

-- PostgreSQL
SELECT1;

📌 100% 자동 치환 가능


✅ 5. TO_CHAR / TO_DATE (형식이 명확한 경우)

-- Oracle
TO_CHAR(dt,'YYYYMMDD')
TO_DATE('20240101','YYYYMMDD')

-- PostgreSQL
TO_CHAR(dt,'YYYYMMDD')
TO_DATE('20240101','YYYYMMDD')

📌 함수 이름/포맷 문자열이 동일해서 그대로 유지 가능

(이건 의외로 안 바꿔도 됨)


✅ 6. 문자열 결합 (단순)

a|| b

  • PostgreSQL도 || 지원
  • 둘 다 문자열(text/varchar)인 경우 자동 치환 불필요

📌 숫자 섞이면 위험 → 그건 ❌ 영역


✅ 7. 기본 집계 함수

Oracle  PostgreSQL
COUNT 동일
SUM 동일
MAX / MIN 동일
AVG 동일

📌 GROUP BY 의미도 동일 → 안전


2️⃣ ❌ 절대 자동 치환하면 안 되는 것 (사람이 책임져야 함)

이 영역은 문법만 맞게 바꿔도 결과가 달라질 수 있음

→ 자동화하면 “조용히 틀린 결과”가 나오는 최악의 구간


❌ 1. ROWNUM / 페이징

-- Oracle
SELECT*
FROM (
SELECT A.*, ROWNUM RN
FROM A
ORDERBY CREATED_ATDESC
)
WHERE RNBETWEEN11AND20;

🚫 자동 치환 금지 이유

  • Oracle은 ROWNUM → ORDER BY 순서
  • PostgreSQL은 ORDER BY → LIMIT/OFFSET
  • 단순 치환하면 조회 결과가 달라짐

👉 반드시 쿼리 의도를 해석해서 재작성


❌ 2. (+) OUTER JOIN

-- Oracle
A.ID= B.A_ID(+)

🚫 자동 치환 금지 이유

  • (+) 위치에 따라 LEFT / RIGHT JOIN 의미가 달라짐
  • 여러 테이블 얽히면 사람도 헷갈림

👉 JOIN 구조 재작성 필수


❌ 3. DECODE

DECODE(status,'A',1,'B',2,0)

🚫 자동 치환 위험

  • CASE WHEN으로 바꾸는 건 가능해 보이지만
  • NULL 처리 / default 처리 차이로 결과 어긋나는 경우 잦음

👉 CASE WHEN 직접 작성 + 테스트


❌ 4. MERGE INTO

MERGEINTO ...

🚫 완전 다른 개념

  • PostgreSQL은 INSERT ... ON CONFLICT
  • 로직 구조 자체가 다름

👉 비즈니스 로직 재작성 대상


❌ 5. 날짜 비교 로직 (TRUNC, 월 계산 등)

TRUNC(sysdate)
TRUNC(order_dt,'MM')

🚫 자동 치환 금지 이유

  • PostgreSQL엔 TRUNC(date) 개념 없음
  • date_trunc()로 대체 가능하지만 의미가 완전히 같지 않음

👉 업무 기준으로 재정의 필요


❌ 6. 숫자 + 문자열 혼합 연산

'ORD-'|| order_no

🚫 Oracle은 암묵적 형변환 허용

🚫 PostgreSQL은 에러 발생

👉 명시적 캐스팅 필요 (order_no::text)


❌ 7. 서브쿼리 안의 ROWNUM / EXISTS 조합

WHEREEXISTS (
SELECT1FROM AWHERE ROWNUM=1
)

🚫 의미 자체가 Oracle 특화

👉 로직 재설계 대상


❌ 8. 힌트 / 옵티마이저 의존 SQL

/*+ INDEX(A IDX_A1) */

🚫 PostgreSQL은 무시하거나 에러

👉 인덱스 설계 + ANALYZE로 접근해야 함


❌ 9. PL/SQL 의존 SQL

  • SELECT ... INTO
  • EXCEPTION WHEN
  • 커서 루프 전제 SQL

🚫 MyBatis SQL로 그대로 못 옮김

👉 애플리케이션 로직으로 이동


3️⃣ 실무 권장 분류 기준 (이렇게 나누면 안전)

🔹 자동 치환 대상

  • 함수 1:1 대응
  • 결과 의미가 명확
  • 정렬/페이징/조인 구조 안 건드림

🔹 수동 전환 대상

  • 페이징
  • JOIN
  • 날짜 계산
  • 비즈니스 분기 로직
  • 성능 의존 SQL

4️⃣ 한 줄 요약 (이 문서의 핵심)

  • 자동 치환은 “문법”이 아니라 “의미가 같을 때만” 허용
  • MyBatis SQL에서
    • NVL, SYSDATE, DUAL → 자동화 가능
    • ROWNUM, MERGE, (+), DECODE → 자동화 금지
  • 틀린 결과는 에러보다 더 위험하다

댓글