NULL과 ‘‘(빈 문자열)
Oracle은 ‘‘도 NULL처럼 처리되는 경우가 있다.
ex | Result |
---|---|
NVL('', 0) |
0 |
'' IS NULL |
true |
'' IS NOT NULL |
false |
PostgreSQL은 기본적으로 NULL과 ‘‘를 엄격히 구분한다.
ex | Result |
---|---|
COALESCE('', 0) |
’’ |
'' IS NULL |
false |
'' IS NOT NULL |
true |
PostgreSQL에서는 입력값을 NULL, ‘’ 둘 중 하나로 통일하거나, 값 처리 부분에서 둘 모두를 고려하도록 해야한다.
Oracle | PostgreSQL |
---|---|
NVL(val, 'false') |
CASE WHEN val IS NULL OR val = '' THEN 'false' ELSE val END |
COALESCE(NULLIF(val, ''), 'false') |
SUBSTR
SUBSTR(strval, position [, length])
함수의 position 인자 처리 방식이 다르다.
Val | Oracle | PostgreSQL |
---|---|---|
> 0 | 1부터 시작하는, 앞에서부터의 위치 | 1부터 시작하는, 앞에서부터의 위치 |
0 | 1과 동일 | 1과 동일. 단, length에 -1의 영향을 끼침 |
< 0 | -1부터 시작하는, 뒤에서부터의 위치 | 1과 동일. 단, length에 n - 1의 영향을 끼침 |
Oracle의 것은 나름 정리되어있다만, PostgreSQL의 것은 이상하다. 그것이 다음과 같은 결과를 만든다:
SQL | Oracle | PostgreSQL |
---|---|---|
SUBSTR('123456789dcba', 4, 3) |
'456' |
'456' |
SUBSTR('123456789dcba', 3, 3) |
'345' |
'345' |
SUBSTR('123456789dcba', 2, 3) |
'234' |
'234' |
SUBSTR('123456789dcba', 1, 3) |
'123' |
'123' |
SUBSTR('123456789dcba', 0, 3) |
'123' |
'12' |
SUBSTR('123456789dcba', -1, 3) |
'a' |
'1' |
SUBSTR('123456789dcba', -2, 3) |
'ba' |
'' |
SUBSTR('123456789dcba', -3, 3) |
'cba' |
'' |
SUBSTR('123456789dcba', -4, 3) |
'dcb' |
'' |
…차라리 에러를 뱉지 그래?
DATE, TIMESTAMP, SYSDATE, CURRENT_DATE, CURRENT_TIMESTAMP, CLOCK_TIMESTAMP, TO_DATE, TO_TIMESTAMP
Oracle의 DATE가 DATETIME(또는 TIMESTAMP)의 약어처럼 쓰이는 것과 달리, PostgreSQL은 둘을 구분한다.
PostgreSQL에서 DATE 값과 함수는 시, 분, 초를 버리므로 이 값이 필요하다면 반드시 TIMESTAMP 용을 사용해야 한다.
Oracle | PostgreSQL |
---|---|
SYSDATE |
CURRENT_TIMESTAMP |
TO_DATE('20211213142345', 'YYYYMMDDHH24MISS') |
TO_TIMESTAMP('20211213142345', 'YYYYMMDDHH24MISS') |
TRUNC(SYSDATE) |
CURRENT_DATE |
하나 더,
PostgreSQL은 성능을 위해 한 트랜잭션 내의 CURRENT_TIMESTAMP
이 모두 같은 값을 반환한다.
DB | Test SQL | Result |
---|---|---|
Oracle | BEGIN DBMS_OUTPUT.PUT_LINE('S=' || TO_CHAR(SYSDATE, 'MI:SS')); DBMS_LOCK.Sleep(1); DBMS_OUTPUT.PUT_LINE('E=' || TO_CHAR(SYSDATE, 'MI:SS')); END; |
S=53:38 E=53:39 |
PostgreSQL | DO $$ DECLARE v_tmp VARCHAR; BEGIN RAISE INFO 'S=%', TO_CHAR(CLOCK_TIMESTAMP(), 'MI:SS'); SELECT Pg_Sleep(1) INTO v_tmp; RAISE INFO 'E=%', TO_CHAR(CLOCK_TIMESTAMP(), 'MI:SS'); END $$; |
S=53:38 E=53:39 |
DO $$ DECLARE v_tmp VARCHAR; BEGIN RAISE INFO 'S=%', TO_CHAR(CURRENT_TIMESTAMP, 'MI:SS'); SELECT Pg_Sleep(1) INTO v_tmp; RAISE INFO 'E=%', TO_CHAR(CURRENT_TIMESTAMP, 'MI:SS'); END $$; |
S=53:38 E=53:38 |
만약, Oracle SYADATE
처럼 매번 새로운 값을 얻어야 한다면
CURRENT_TIMESTAMP
대신 CLOCK_TIMESTAMP()
를 사용해야 한다.
REGEXP_REPLACE
함수명은 같지만, 시그니처부터 Oracle과 PostgreSQL은 다음처럼 서로 다르다:
DB | Signature |
---|---|
Oracle | REGEXP_REPLACE(source, pattern [, replacement [, position [, occurrence [, flags ]]]]) |
PostgreSQL | REGEXP_REPLACE(source, pattern, replacement [, flags ]) |
기본 동작도 Oracle은 모든 일치 부분을 바꾸지만, PostgreSQL은 처음 일치 부분만 바꾼다.
반드시 추가인자(Oracle: occurrence, PostgreSQL: flags)로 맞춰줘야 한다.
occ | Oracle | PostgreSQL |
---|---|---|
* | REGEXP_REPLACE('aabcabac', 'ab', 'AB') |
REGEXP_REPLACE('aabcabac', 'ab', 'AB', 'g') |
1 | REGEXP_REPLACE('aabcabac', 'ab', 'AB', 1, 1) |
REGEXP_REPLACE('aabcabac', 'ab', 'AB') |