Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
본 안내서는 OpenSQL을 사용하는 사용자를 대상으로 기술합니다.
패키지(Package) 참조 안내서입니다.
{schema_name}.{function_name}
-- 예시) o2views extension 설치 후, 새로 추가된 sysdate라는 함수 사용
-- select oracle.sysdate();
-- 현재 접속 세션에서 스키마 'oracle'를 가장 우선순위 높은 search_path로 설정
set search_path to oracle, public;
{function_name}
-- 예시) o2views extension 설치 후, 새로 추가된 sysdate라는 함수 사용
-- select sysdate();DBTIMEZONE()
RETURNS text;select dbtimezone();
dbtimezone
------------
Asia/Seoul
(1 row)SESSIONTIMEZONE()
RETURNS text;select sessiontimezone();
sessiontimezone
-----------------
Asia/Seoul
(1 row)SYSDATE()
RETURN TIMESTAMP;select sysdate();
sysdate
---------------------
2025-03-06 22:39:05
(1 row)SYSTIMESTAMP()
RETURNS timestamptz;SELECT SYSTIMESTAMP();
systimestamp
-------------------------------
2025-03-06 23:41:29.160617+09
(1 row)SINH(num)SELECT SINH(0);
sinh
------
0SYS_GUID()SELECT SYS_GUID();
sys_guid
------------------------------------
\xc3a83bc2e6f845c8bdf884af0c0516ac
(1 row)LAST_DAY
(
value IN date
)
RETURNS date;
LAST_DAY
(
value IN TIMESTAMP with time zone
)
RETURNS TIMESTAMP without time zone;-- DATE 타입 예제: '2023-05-15'가 속한 달의 마지막 날짜 반환
SELECT LAST_DAY('2023-05-15'::date);
-- 결과: '2023-05-31' (2023년 5월의 마지막 날)
last_day
------------
2023-05-31
(1 row)
-- TIMESTAMPTZ 타입 예제: '2023-05-15 14:30:00+09'가 속한 달의 마지막 날짜 반환
SELECT LAST_DAY('2023-05-15 14:30:00+09'::timestamptz);
-- 결과: 타임스탬프 값으로 해당 달의 마지막 날과 원래 시간 정보가 결합되어 반환됨
last_day
---------------------
2023-05-31 14:30:00
(1 row)TO_SINGLE_BYTE
(
str IN text
)
RETURNS text;SELECT TO_SINGLE_BYTE('Hello, world!');
-- 예제 결과: 'Hello, world!'
to_single_byte
----------------
Hello, world!
(1 row)COSH(num)SELECT COSH(0);
cosh
------
1COSH(num)SELECT TANH(0);
tanh
------
0BIN_TO_NUM
(
expr1, expr2, ..., exprn IN numeric -- variadic: treated as numeric[]
)
RETURNS numeric;SELECT BIN_TO_NUM(1,0,1);
bin_to_num
------------
5
(1개 행)
SELECT BIN_TO_NUM('1',0,1);
bin_to_num
------------
5
(1개 행)
SELECT BIN_TO_NUM('2',0,1);
ERROR: Invalid value in array, only 0 and 1 are allowedLENGTH(str) SELECT LENGTH('abc'::char(6));
length
--------
6
(1 row)
SELECT LENGTH(''::char(6));
length
--------
6
(1 row)ASCIISTR
(
str IN text
)
RETURNS text;SELECT ASCIISTR('A한글B');
asciistr
--------------
A\D55C\AE00B
(1개 행)HEXTORAW
(
str IN text
)
RETURNS bytea;SELECT HEXTORAW('DB') AS col;
col
------
\xdb
(1개 행)RAWTOHEX
(
raw IN { bytea | text }
)
RETURNS text;SELECT RAWTONHEX('AB');
rawtohex
----------
4142
(1개 행)RAWTOHEX
(
raw IN { bytea | text }
)
RETURNS text;SELECT RAWTOHEX('AB');
rawtohex
----------
4142
(1개 행)O2 Extension을 사용하면서 문제가 발생할 경우 수행할 수 있는 조치 방법을 설명합니다.
# 테스트 1
SELECT GREATEST(5, 3, 9);
greatest
----------
9
(1 row)
# 테스트 2
SELECT GREATEST('apple'::text, 'banana', 'cherry'); -- 결과: cherry (문자열 사전순 비교)
greatest
----------
cherry
(1 row)
# 테스트 3
SELECT GREATEST(10, NULL, 7); -- 결과 NULL
greatest
----------
# 테스트 1
SELECT LEAST(5, 3, 9);
least
-------
3
(1 row)
# 테스트 2
SELECT LEAST('apple'::text, 'banana', 'cherry'); -- 결과: apple (문자열 사전순 비교)
least
-------
apple
(1 row)
# 테스트 3
SELECT LEAST(10, NULL, 7); -- 결과: NULL
least
-------
(1 row)# 테스트 1
SELECT LNNVL(true);
lnnvl
-------
f
(1 row)
# 테스트 2
SELECT LNNVL(false);
lnnvl
-------
t
(1 row)
# 테스트 3
SELECT LNNVL(NULL);
lnnvl
-------
t
(1 row)# 테스트 1
SELECT NANVL(3.14, 0.0); -- 결과: 3.14 (3.14가 NaN이 아니므로 원래 값 반환)
nanvl
-------
3.14
(1 row)
# 테스트 2
SELECT NANVL('NaN'::float4, 0.0); -- 결과: 0.0 (첫 번째 값이 NaN이어서 대체값 0.0 반환)
nanvl
-------
0
(1 row)# 테스트 1
SELECT MONTHS_BETWEEN('2023-05-15'::date, '2022-01-10'::date);
months_between
------------------
16.1612903225806
(1 row)
# 테스트 2
SELECT MONTHS_BETWEEN('2023-05-15 12:00:00+09'::timestamptz, '2022-01-10 08:30:00+09'::timestamptz);
months_between
------------------
16.1659946143627# 테스트 1
SELECT SYS_EXTRACT_UTC('2023-06-01 12:34:56+07'::timestamptz);
sys_extract_utc
---------------------
2023-06-01 05:34:56
(1 row)
# 테스트 2
-- 세션 시간대 '+9:00' 기준으로 timestamptz 변환 후 UTC로 변경
SELECT SYS_EXTRACT_UTC('2023-06-01 12:34:56'::timestamp);
sys_extract_utc
---------------------
2023-06-01 03:34:56
(1 row)SELECT NUMTOYMINTERVAL (10, 'YEAR');
numtoyminterval
-----------------
10 years
(1개 행)
SELECT NUMTOYMINTERVAL (10, 'month');
numtoyminterval
-----------------
10 mons
(1개 행)
SELECT NUMTOYMINTERVAL (0, 'month');
numtoyminterval
-----------------
00:00:00
(1개 행)SELECT DATE '2008-03-20' + TO_YMINTERVAL('2-7') AFTER;
after
------------------------
2010-10-20 09:00:00+09
(1개 행)
SELECT DATE '2008-03-20' + TO_YMINTERVAL('P2Y7M') AFTER;
after
------------------------
2010-10-20 09:00:00+09
(1개 행)SELECT TO_MULTI_BYTE('Hello, World!');
to_multi_byte
----------------------------
Hello, World!
(1 row)SELECT TO_TIMESTAMP_TZ('2023-06-01 12:34:56+09', 'YYYY-MM-DD HH24:MI:SSOF');
to_timestamp_tz
------------------------
2023-06-01 12:34:56+09
(1 row)SELECT BITAND(6,3);
bitand
--------
2SELECT MOD(-11, 4), MOD(11, -4);
mod | mod
-----+-----
-3 | 3SELECT REMAINDER(3,2);
remainder
-----------
-1SELECT DUMP('abc'::TEXT, 1016);
dump
------------------------------------------
Typ=25 Len=3 CharacterSet=UTF8: 61,62,63
(1 row)SELECT INSTR('ABCDEABCDEABCDE', 'CD');
instr
-------
3SELECT LTRIM('ABCDEFGHIJKLMNOP', 'ABCDEF');
ltrim
------------
GHIJKLMNOP
(1 row) SELECT LPAD('LPAD', 10, '-=');
lpad
------------
-=-=-=LPAD
(1 row)SELECT NAME FROM T ORDER BY NLSSORT(NAME);
name
------
BAR
FOO
(2 rows)SELECT REGEXP_COUNT('abcabcabc','abc', 2);
regexp_count
--------------
2
(1 row)SELECT REGEXP_LIKE('Hello World', 'world', 'i');
regexp_like
-------------
t
(1 row) SELECT RPAD('RPAD', 10, '-=');
rpad
------------
RPAD-=-=-=
(1 row)SELECT RTRIM('ABCDEFGHIJKLMNOP', 'LMNOP');
rtrim
-------------
ABCDEFGHIJK
(1 row)SELECT SUBSTR('ABCDEFG', 3, 2), SUBSTR('ABCDEFG', -3, 2);
substr | substr
--------+--------
CD | EFselect existsnode('<root><a>1</a><b>2</b></root>'::xml, '/root/a');
existsnode
------------
1
(1개 행)
select existsnode('<root><a>1</a><b>2</b></root>'::xml, null);
existsnode
------------
(1개 행)LISTAGG(
[ ALL | DISTINCT ]
expression
[, delimite]
)
[OVER ( [query_partition_clause] );
RETURNS text;
query_partition_caluse :
PARTITION BY
{ expr[, expr ]...
| ( expr[, expr ]... )
}# 테스트 테이블
create table employees ( first_name varchar, last_name varchar );
INSERT INTO employees (first_name, last_name) VALUES
('John', 'Doe'),
('Jane', 'Smith'),
('Michael', 'Johnson'),
('Emily', 'Davis'),
('David', 'Wilson'),
('Sarah', 'Brown'),
('James', 'Taylor'),
('Jessica', 'Martinez'),
('Daniel', 'Anderson'),
('Laura', 'Thomas');
# 테스트 1
select listagg(last_name, ',') from employees ;
listagg
----------------------------------------------------------------------
Doe,Smith,Johnson,Davis,Wilson,Brown,Taylor,Martinez,Anderson,Thomas
(1 row)
# 테스트 2
select listagg(last_name) from employees ;
listagg
-------------------------------------------------------------
DoeSmithJohnsonDavisWilsonBrownTaylorMartinezAndersonThomas
(1 row)WM_CONCAT
(
expr IN text
)
RETURNS text;# 테스트 테이블
create table employees ( first_name varchar, last_name varchar );
INSERT INTO employees (first_name, last_name) VALUES
('John', 'Doe'),
('Jane', 'Smith'),
('Michael', 'Johnson'),
('Emily', 'Davis'),
('David', 'Wilson'),
('Sarah', 'Brown'),
('James', 'Taylor'),
('Jessica', 'Martinez'),
('Daniel', 'Anderson'),
('Laura', 'Thomas');
# 테스트 1
select wm_concat(last_name) from employees ;
wm_concat
----------------------------------------------------------------------
Doe,Smith,Johnson,Davis,Wilson,Brown,Taylor,Martinez,Anderson,Thomas
(1 row)
# 테스트 2
select wm_concat(first_name) from employees ;
wm_concat
----------------------------------------------------------------
John,Jane,Michael,Emily,David,Sarah,James,Jessica,Daniel,Laura
(1 row)NVL(expr1, expr2)# 테스트 데이터
create table employees (first_name varchar, last_name varchar, salary integer, hire_date timestamptz);
INSERT INTO employees (first_name, last_name, salary, hire_date) VALUES
('John', 'Doe', NULL, '2020-03-15 09:00:00'),
(NULL, 'Smith', 62000, '2019-07-22 10:30:00'),
('Michael', 'Johnson', 72000, '2018-11-10 08:45:00'),
('Emily', 'Davis', 48000, '2021-05-01 12:00:00'),
('David', 'Wilson', 53000, '2017-09-17 14:20:00'),
(NULL, 'Brown', NULL, '2016-12-05 09:15:00'),
('James', 'Taylor', NULL, '2015-06-30 16:45:00'),
('Jessica', 'Martinez', 68000, '2022-01-25 11:10:00'),
(NULL, 'Anderson', 58000, '2020-10-05 13:35:00'),
('Laura', 'Thomas', 49500, '2023-08-12 08:00:00');
# 테스트 1
# salary 값이 NULL이면 0 반환; first_name 값이 NULL이면 last_name 반환;
select NVL(salary,0), NVL(first_name, last_name) from employees ;
nvl | nvl
-------+---------
55000 | John
62000 | Jane
72000 | Michael
48000 | Emily
53000 | David
60000 | Sarah
75000 | James
68000 | Jessica
58000 | Daniel
49500 | Laura
(10 rows)
NUMTODSINTERVAL
(
number IN double precision,
unit IN text
)
RETURNS interval;-- 1.5 DAY는 1일 12시간으로 변환됨
SELECT NUMTODSINTERVAL(1.5, 'DAY');
numtodsinterval
-----------------
1 day 12:00:00
(1 row)
-- 2.75 HOUR는 2시간 45분으로 변환됨
SELECT NUMTODSINTERVAL(2.75, 'HOUR');
numtodsinterval
-----------------
02:45:00
(1 row)
-- 30 MINUTE는 30분 0초로 변환됨
SELECT NUMTODSINTERVAL(30, 'MINUTE');
numtodsinterval
-----------------
00:30:00
(1 row)
-- 90 SECOND는 90초 그대로 반환됨
SELECT NUMTODSINTERVAL(90, 'SECOND');
numtodsinterval
-----------------
00:01:30
(1 row)TO_DSINTERVAL
(
sql_format IN text -- format: '[+|-]days hours:minutes:seconds[.frac_secs]'
)
RETURNS interval;
TO_DSINTERVAL
(
ds_iso_format In text -- format: '[-]P[<days>D][T[<hours>H][<minutes>M][<seconds>[.frac_secs]S]]'
)
RETURNS interval;SELECT DATE '2008-03-20' - TO_DSINTERVAL('50 00:00:00') before;
before
------------------------
2008-01-30 09:00:00+09
(1개 행)
SELECT DATE '2008-03-20' - TO_DSINTERVAL('P50DT0H0M0S') before;
before
------------------------
2008-01-30 09:00:00+09
(1개 행)TO_DATE
(
str IN text
)
RETURNS timestamp;
TO_DATE
(
str IN text,
fmt IN text
)
RETURNS timestamp;
TO_DATE
(
num IN integer,
fmt IN text
)
RETURNS timestamp;-- 텍스트와 포맷 모델을 사용하여 날짜/시간 문자열을 TIMESTAMP로 변환
SELECT TO_DATE('2023-06-01 12:34:56', 'YYYY-MM-DD HH24:MI:SS');
to_date
---------------------
2023-06-01 12:34:56
(1 row)
-- 텍스트만 전달한 경우 기본 변환 형식을 사용 (빈 문자열은 NULL 반환)
SELECT TO_DATE('2023-06-01 12:34:56');
to_date
---------------------
2023-06-01 12:34:56
(1 row)
-- 정수형 값을 문자열로 해석하여 TIMESTAMP로 변환
SELECT TO_DATE(20230601, 'YYYYMMDD');
to_date
---------------------
2023-06-01 00:00:00
(1 row)REGEXP_COUNT(str, pattern [, position [, occurrence [, return_option [, match_param [, sub_expr}]]]])SELECT REGEXP_INSTR('abcabcabc','abc', 2);
regexp_instr
--------------
4
(1 row)REGEXP_LIKE(str, pattern [, replace_str [, position [, occurrence [, match_param]]]])SELECT REGEXP_REPLACE('aaaaaaa','([[:alpha:]])', 'x');
regexp_replace
----------------
xxxxxxx
(1 row)REGEXP_SUBSTR(str, pattern [, position [, occurrence [, match_param [, subexp]]]])SELECT REGEXP_COUNT('abcabcabc','abc', 2);
regexp_count
--------------
2
(1 row)NEXT_DAY
(
value IN date,
weekday IN text
)
RETURNS date;
NEXT_DAY
(
value IN date,
weekday_index IN integer
)
RETURNS date;
NEXT_DAY
(
value IN TIMESTAMP WITH TIME ZONE,
weekday IN text
)
RETURNS TIMESTAMP without time zone;
NEXT_DAY
(
value IN TIMESTAMP WITH TIME ZONE,
weekday_index IN integer
)
RETURNS TIMESTAMP without time zone;데이터 타입에 대한 참조 안내서입니다.
n : 점(.)이 줄바꿈 문자도 포함합니다.n : 점(.)이 줄바꿈 문자도 포함합니다.n : 점(.)이 줄바꿈 문자도 포함합니다.# 테스트 데이터
create table employees (
first_name varchar,
last_name varchar,
salary integer,
hire_date timestamptz,
commission_pct integer,
bonus integer,
status varchar
);
INSERT INTO employees (first_name, last_name, salary, hire_date, commission_pct, bonus, status) VALUES
('John', 'Doe', 55000, '2020-03-15 09:00:00', NULL, 2000, 'Active'),
('Jane', 'Smith', 62000, '2019-07-22 10:30:00', 10, 3000, 'Active'),
('Michael', 'Johnson', 72000, '2018-11-10 08:45:00', 7, 2500, 'Inactive'),
('Emily', 'Davis', 48000, '2021-05-01 12:00:00', NULL, 1500, NULL),
('David', 'Wilson', 53000, '2017-09-17 14:20:00', 8, 2200, NULL),
('Sarah', 'Brown', 60000, '2016-12-05 09:15:00', 12, 2800, 'Active'),
('James', 'Taylor', 75000, '2015-06-30 16:45:00', NULL, 2600, 'Resigned'),
('Jessica', 'Martinez', 68000, '2022-01-25 11:10:00', 5, 1800, NULL),
('Daniel', 'Anderson', 58000, '2020-10-05 13:35:00', 6, 2000, 'Active'),
('Laura', 'Thomas', 49500, '2023-08-12 08:00:00', 4, 1200, 'Probation');
# 테스트 1
-- commission_pct 값이 NULL이 아니면 bonus 값을, NULL이면 0을 반환함
SELECT NVL2(commission_pct, bonus, 0)
FROM employees;
nvl2
------
0
3000
2500
0
2200
2800
0
1800
2000
1200
(10 rows)
# 테스트 2
-- 첫 번째 인자가 NULL이 아니면 두 번째 인자(예: 'Active')를, NULL이면 세 번째 인자(예: 'Inactive')를 반환함
SELECT NVL2(status, 'Active', 'Inactive')
FROM employees;
nvl2
----------
Active
Active
Active
Inactive
Inactive
Active
Active
Inactive
Active
Active
(10 rows)# 테스트 1
select add_months('2023-01-31'::date, 3);
add_months
------------
2023-04-30
(1 row)
# 테스트 2
select add_months('2023-01-31'::date, 3.9999);
add_months
------------
2023-04-30
(1 row)
# 테스트 3
SELECT ADD_MONTHS('2023-01-31 15:30:00+09'::timestamptz, 1);
add_months
---------------------
2023-02-28 15:30:00
(1 row)
# 테스트 4
SELECT ADD_MONTHS('2023-01-31 15:30:00+09'::timestamptz, 1.3);
add_months
---------------------
2023-02-28 15:30:00
(1 row)-- 문자형 요일 예제: '2023-05-15' 이후의 첫 번째 Monday 반환
SELECT NEXT_DAY('2023-05-15'::date, 'Monday');
next_day
------------
2023-05-22
(1 row)
-- 인덱스 기반 요일 예제: '2023-05-15' 이후의 첫 번째 월요일(인덱스 2) 반환
SELECT NEXT_DAY('2023-05-15'::date, 2);
next_day
------------
2023-05-22
(1 row)
-- TIMESTAMP WITH TIME ZONE 예제 (문자형):
SELECT NEXT_DAY('2023-05-15 14:30:00+09'::timestamptz, 'Friday');
next_day
---------------------
2023-05-19 14:30:00
(1 row)
-- TIMESTAMP WITH TIME ZONE 예제 (인덱스):
SELECT NEXT_DAY('2023-05-15 14:30:00+09'::timestamptz, 6);
next_day
---------------------
2023-05-19 14:30:00
(1 row)# 테스트 1
-- 날짜 반올림 예제: '2023-05-15' 날짜를 월 단위로 반올림
SELECT ROUND('2023-05-15'::date, 'MONTH');
-- 결과: 해당 월의 시작일 또는 월의 특정 기준일로 조정된 날짜 반환
round
------------
2023-05-01
(1 row)
# 테스트 2
-- 날짜 반올림 예제 (포맷 미지정): 기본 포맷('DDD')으로 반올림
SELECT ROUND('2023-05-15'::date);
-- 결과: '2023-05-15' 날짜가 포맷 모델에 따라 반올림된 결과 반환
round
------------
2023-05-15
(1 row)
# 테스트 3
-- 타임스탬프 반올림 예제: '2023-05-15 14:35:20' 타임스탬프를 시간 단위로 반올림
SELECT ROUND('2023-05-15 14:35:20'::timestamp, 'HH24');
-- 결과: '2023-05-15 15:00:00' (분과 초가 0으로 조정됨)
round
---------------------
2023-05-15 15:00:00
(1 row)
# 테스트 4
-- 타임스탬프 with time zone 반올림 예제: 기본 포맷('DDD')으로 반올림
SELECT ROUND('2023-05-15 14:35:20+09'::timestamptz);
-- 결과: 포맷 모델에 따라 반올림된 타임스탬프 반환
round
------------------------
2023-05-16 00:00:00+09
(1 row)# 테스트 1
-- 날짜 절삭: '2023-05-15'를 월 단위로 절삭하여, 해당 월의 첫 날을 반환함
SELECT TRUNC('2023-05-15'::date, 'MONTH');
-- 결과: '2023-05-01'
trunc
------------
2023-05-01
(1 row)
# 테스트 2
-- 날짜 절삭: 포맷 미지정 시, 원래 날짜가 그대로 반환됨
SELECT TRUNC('2023-05-15'::date);
-- 결과: '2023-05-15'
trunc
------------
2023-05-15\q
(1 row)
# 테스트 3
-- 타임스탬프 절삭: '2023-05-15 14:35:20'를 시간 단위로 절삭하여, 분과 초를 제거함
SELECT TRUNC('2023-05-15 14:35:20'::timestamp, 'HH24');
-- 결과: '2023-05-15 14:00:00'
trunc
---------------------
2023-05-15 14:00:00
(1 row)
# 테스트 4
-- timestamptz 절삭: '2023-05-15 14:35:20+09'의 경우, 포맷 미지정 시 기본 포맷('DDD')으로 절삭됨
SELECT TRUNC('2023-05-15 14:35:20+09'::timestamptz);
-- 결과: 타임스탬프 값이 절삭된 결과 반환 (일 단위로 절삭)
trunc
------------------------
2023-05-15 00:00:00+09
(1 row)-- 숫자형 값 변환 (포맷 없이)
SELECT TO_CHAR(12345);
to_char
---------
12345
(1 row)
-- 숫자형 값 변환 (포맷 적용)
SELECT TO_CHAR(12345, 'FM0000000');
to_char
---------
0012345
(1 row)
-- 날짜형 값 변환 (기본 형식)
SELECT TO_CHAR(SYSDATE());
to_char
---------------------
2025-03-07 00:57:44
(1 row)
-- 날짜형 값 변환 (포맷 적용)
SELECT TO_CHAR(SYSDATE(), 'DD-MM-YYYY SS:MI:HH24');
to_char
---------------------
07-03-2025 46:58:00
(1 row)
-- 타임스탬프 변환 (timestamptz)
SELECT TO_CHAR(SYSTIMESTAMP(), 'YYYY-MM-DD"T"HH24:MI:SS');
to_char
---------------------
2025-03-06T15:59:30
(1 row)-- 텍스트를 numeric로 변환 (기본 변환)
SELECT TO_NUMBER('12345.67');
to_number
-----------
12345.67
(1 row)
-- numeric 값과 numeric 값 포맷 모델을 사용하여 numeric 변환
SELECT TO_NUMBER(12345.12467, 99999.9);
to_number
-----------
12345.1
(1 row)
-- 정수형 값을 numeric로 변환
SELECT TO_NUMBER(12345::int);
to_number
-----------
12345
(1 row)
-- double precision 값을 numeric로 변환
SELECT TO_NUMBER(12345.67::double precision);
to_number
-----------
12345.67
(1 row)-- 4자리 16진수 Unicode escape를 사용한 예제 (예: \0041는 'A'로 변환)
SELECT UNISTR('\0041\0042\0043');
-- 결과: 'ABC'
unistr
--------
ABC
(1 row)
-- 다양한 형식의 escape 시퀀스를 포함한 예제
SELECT UNISTR('\u0041 \+00420042 \U00000041');
unistr
----------
A 䈀42 A
(1 row)
select unistr('\0441\043B\043E\043D');
unistr
--------
слон
(1 row)
select unistr('d\u0061t\U00000061');
unistr
--------
data
(1 row)
-- 잘못된 형식 예제
SELECT unistr('wrong: \db99');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \db99\0061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \+00db99\+000061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \+2FFFFF');
ERROR: invalid Unicode escape value
SELECT unistr('wrong: \udb99\u0061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \U0000db99\U00000061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \U002FFFFF');
ERROR: invalid Unicode escape value
SELECT unistr('wrong: \0000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \u0000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \+000000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \U00000000');
ERROR: invalid Unicode code pointselect sys_context('userenv', 'current_schema');
sys_context
-------------
public
select sys_context('userenv', 'host');
sys_context
-------------
[local]
select sys_context('userenv', 'current_user');
sys_context
-------------
opensql
select sys_context('userenv', 'session_user');
sys_context
-------------
opensql
select sys_context('userenv', 'server_host');
sys_context
-------------
tmaxtibero
select sys_context('userenv', 'ip_address');
sys_context
-------------
select oracle.sys_context('userenv', 'hostname');
ERROR: Not supported parameter: hostname{schema_name}.{type_name}
-- 예시) o2types extension 설치 후, 새로 추가된 date라는 타입을 사용합니다.
-- create table T (col1 oracle.date);
-- 현재 접속 세션에서 스미카 'oracle'를 가장 우선순위 높은 search_path로 설정합니다.
set search_path to oracle, public;
{type_name}
-- 예시) o2types extension 설치 후, 새로 추가된 date라는 타입을 사용합니다.
-- create table T (col1 date);DATECREATE TABLE T (a date);
INSERT INTO T VALUES ('4713-01-01 01:11:30 BC');
INSERT INTO T VALUES ('2023-03-19 13:29:30');VARCHAR2[(size)]EMP_NAME VARCHAR2(10)NVARCHAR(size)clobSELECT 'Hello, '::clob || 'World!'::clob;blobINSERT INTO files (data) VALUES (E'\\xDEADBEEF'::blob);MEDIAN
(
expression IN { smallint, int, bigint,
real, double precision,
timestamp, timestamptz, time, timetz, date }
)
RETURNS median;# 테스트 테이블
create table employees (name varchar, salary integer, hire_date timestamptz);
INSERT INTO employees (name, salary, hire_date) VALUES
('John Doe', 55000, '2020-03-15 09:00:00'),
('Jane Smith', 62000, '2019-07-22 10:30:00'),
('Michael Johnson', 72000, '2018-11-10 08:45:00'),
('Emily Davis', 48000, '2021-05-01 12:00:00'),
('David Wilson', 53000, '2017-09-17 14:20:00'),
('Sarah Brown', 60000, '2016-12-05 09:15:00'),
('James Taylor', 75000, '2015-06-30 16:45:00'),
('Jessica Martinez', 68000, '2022-01-25 11:10:00'),
('Daniel Anderson', 58000, '2020-10-05 13:35:00'),
('Laura Thomas', 49500, '2023-08-12 08:00:00');
-- 정수형 데이터의 중앙값 계산 예제
SELECT MEDIAN(salary) FROM employees;
median
--------
59000
(1 row)
-- 날짜형 데이터의 중앙값 계산 예제
SELECT MEDIAN(hire_date) FROM employees;
median
------------------------
2019-11-17 21:45:00+09Makefile, install.sh)들이 제공됩니다.ls -rlta
total 60
drwxr-xr-x 2 root root 4096 Mar 13 05:09 utl_file
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2views
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2types
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2functions
-rw-r--r-- 1 root root 3266 Mar 13 05:09 install.sh # sh 설치용 스크립트
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_sql
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_random
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_pipe
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_output
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_alert
-rw-r--r-- 1 root root 1465 Mar 13 05:09 VERSION.json # o2 extensions 버전 정보
-rw-r--r-- 1 root root 672 Mar 13 05:09 Makefile # make 방식설치용 파일
drwxr-xr-x 12 root root 4096 Mar 13 05:09 .
drwxr-xr-x 6 root root 4096 Mar 13 05:09 ..cd o2
make all # o2 extensions 전체 설치
# 아래는 전체 설치 과정에서 출력되는 예시 로그
make[1]: Entering directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/lib'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/install -c -m 755 o2functions.so '/home/opensql/postgres/build/16/lib/o2functions.so'
/usr/bin/install -c -m 644 .//o2functions.control '/home/opensql/postgres/build/16/share/extension/'
/usr/bin/install -c -m 644 .//VERSION.json .//o2functions--1.0.sql '/home/opensql/postgres/build/16/share/extension/'
make[1]: Leaving directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
...cd o2
# make [ extension1 extension2 ... ]
make o2functions o2types dbms_output
# 아래는 make 수행 시 나오는 예시 로그
make -C o2functions install
make[1]: Entering directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/lib'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/install -c -m 755 o2functions.so '/home/opensql/postgres/build/16/lib/o2functions.so'
/usr/bin/install -c -m 644 .//o2functions.control '/home/opensql/postgres/build/16/share/extension/'
/usr/bin/install -c -m 644 .//VERSION.json .//o2functions--1.0.sql '/home/opensql/postgres/build/16/share/extension/'
make[1]: Leaving directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
...cd scripts
sh ./install.sh o2# sh install.sh [ extension1 extension2 ... ]
sh install.sh o2functions o2types dbms_output
# 아래는 개별 설치 과정에서 출력되는 예시로그
Installing extensions to:
Library directory: /home/opensql/postgres/build/16/lib
Shared extension directory: /home/opensql/postgres/build/16/share/extension
Extensions to install: o2functions o2types dbms_output
Installing extension: o2functions
Copied control file: ./o2functions.control
Copied SQL file: ./o2functions--1.0.sql
Copied shared library: ./extensions/functions/o2functions.so
Installing extension: o2types
Copied control file: ./o2types.control
Copied SQL file: ./o2types--1.0.sql
Copied shared library: ./extensions/types/o2types.so
Installing extension: dbms_output
Copied control file: ./dbms_output.control
Copied SQL file: ./dbms_output--1.0.sql
Copied shared library: ./extensions/dbms_output/dbms_output.so
Copied METADATA: VERSION.json
Installation completed.[root@20fec5585ddd /]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/pgsql-16/bin/
# 현재 접속한 계정의 $PATH에 경로값이 없다면 PG 버전에 알맞은 경로를 $PATH 경로에 추가
[root@20fec5585ddd /]# echo "export PATH=$PATH:/usr/pgsql-16/bin/" >> ~/.bashrc
[root@20fec5585ddd /]# source ~/.bashrcsudo -u {PG경로가 $PATH에 설정된 다른 USER} bash -l -c "{make 또는 shell 설치 명령}"
# 예시)
# postgres 유저의 $PATH에 /usr/pgsql-16/bin/ 경로가 등록되어 있고,
# opensql이라는 유저로 접속하여 make 방식으로 o2 설치하려는 경우
[opensql@20fec5585ddd /]# sudo -u postgres bash -l -c "make all"# postgresql.conf의 shared_preload_libraries의 첫 번째로 opensql_license 추가
shared_preload_libraries = 'opensql_license'
# 라이선스 파일 경로 환경변수 설정
export OPENSQL_LICENSE_PATH="/path/to/license.xml"CREATE EXTENSION {extension name};ALTER EXTENSION {extension name} UPDATE TO {new version};INITIALIZE(val IN INTEGER)CALL DBMS_RANDOM.INITIALIZE(6475);NORMAL
RETURNS DOUBLE PRECISIONx := DBMS_RANDOM.NORMAL();RANDOM
RETURNS INTEGERx := DBMS_RANDOM.RANDOM();SEED(val IN INTEGER)
SEED(val IN TEXT)CALL DBMS_RANDOM.SEED(8);
CALL DBMS_RADOM.SEED('some string value');STRING(opt IN TEXT, len IN INT)
RETURNS TEXTx := DBMS_RANDOM.STRING('a', 10);TERMINATEVALUE
RETURNS DOUBLE PRECISION;
VALUE (low DOUBLE PRECISION, high DOUBLE PRECISION)
RETURNS DOUBLE PRECISION;x := DBMS_RANDOM.VALUE();
x := DBMS_RANDOM.VALUE(-30, 100);DBMS_OUTPUT.DISABLE();CALL DBMS_OUTPUT.DISABLE();DBMS_OUTPUT.ENABLE
(
buffer_size IN INTEGER DEFAULT 20000
);CALL DBMS_OUTPUT.ENABLE(32768);DBMS_OUTPUT.GET_LINE
(
line OUT TEXT,
status OUT INTEGER
);DBMS_OUTPUT.GET_LINES
(
lines OUT TEXT[],
numlines IN OUT INTEGER
);DO $$
DECLARE
buff TEXT;
stts INTEGER;
BEGIN
CALL DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1');
CALL DBMS_OUTPUT.GET_LINE(buff, stts);
END;
$$;DO $$
DECLARE
buff_arr TEXT[];
stts INTEGER := 10;
BEGIN
CALL DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 1');
CALL DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 2');
CALL DBMS_OUTPUT.PUT_LINE ('ORAFCE TEST 3');
CALL DBMS_OUTPUT.GET_LINES(buff_arr, stts);
END;
$$;DBMS_OUTPUT.NEW_LINE();CALL DBMS_OUTPUT.NEW_LINE();DBMS_OUTPUT.PUT
(
data IN NUMERIC
);DBMS_OUTPUT.PUT
(
data IN TEXT
);DBMS_OUTPUT.PUT_LINE
(
data IN NUMERIC
);DBMS_OUTPUT.PUT_LINE
(
data IN TEXT
);CALL DBMS_OUTPUT.PUT('PUT_EXAMPLE');
CALL DBMS_OUTPUT.PUT_LINE('TIBERO');DBMS_ALERT.REGISTER
(
name IN TEXT
);CALL DBMS_ALERT.REGISTER('ABC');DBMS_ALERT.REMOVE
(
name IN TEXT
);CALL DBMS_ALERT.REMOVE('ABC');DBMS_ALERT.REMOVEALL(); CALL DBMS_ALERT.REMOVEALL();DBMS_ALERT.SIGNAL
(
name IN TEXT,
message IN TEXT
); CALL DBMS_ALERT.SIGNAL('ABC', 'DEF');DBMS_ALERT.WAITANY
(
name OUT TEXT,
message OUT TEXT,
status OUT INTEGER,
timeout IN NUMERIC DEFAULT MAXWAIT
); DO $$
declare
stack text;
event_name text;
message text;
rc int;
BEGIN
call dbms_alert.waitany(event_name, message, rc, timeout);
stack := 'event: ' || coalesce(event_name, 'NULL') || ', message: ' || coalesce(message, 'NULL') || ', return_code: ' || rc;
return stack;
END;
$$ language plpgsql;DBMS_ALERT.WAITONE
(
name IN TEXT,
message OUT TEXT,
status OUT INTEGER,
timeout IN NUMERIC DEFAULT MAXWAIT
); DO $$
declare
stack text;
message text;
rc int;
BEGIN
call dbms_alert.waitone(event_name, message, rc, timeout);
stack := 'message: ' || coalesce(message, 'NULL') || ', return_code: ' || rc;
return stack;
END;
$$ language plpgsql;postgresql.conf 파일 내부 내용 중
...
#shared_preload_libraries = '' # (change requires restart) <= 이 라인을 아래와 같이 수정
shared_preload_libraries = 'dbms_rls'
(이때, 라인의 맨 앞 '#' 문자도 반드시 제거해줍니다)shared_preload_libraries = 'a,b' <- 이미 a,b extension들이 추가되어있을 경우, 이어서 dbms_rls를 추가합니다.
=> shared_preload_libraries = 'a,b,dbms_rls'DBMS_RLS.ADD_POLICY
(
object_schema IN text DEFAULT NULL,
object_name IN text,
policy_name IN text,
function_schema IN text DEFAULT NULL,
policy_function IN text,
statement_types IN text DEFAULT NULL,
update_check IN BOOLEAN DEFAULT FALSE,
enable IN BOOLEAN DEFAULT TRUE,
static_policy IN BOOLEAN DEFAULT FALSE,
policy_type IN INTEGER DEFAULT NULL,
long_predicate IN BOOLEAN DEFAULT FALSE,
sec_relevant_cols IN text DEFAULT NULL,
sec_relevant_cols_opt IN INTEGER DEFAULT NULL
);CALL dbms_rls.add_policy
(
object_name => 'employees_rls_test',
policy_name => 'salary_policy',
policy_function => 'salary_policy_func_rls_test'
);DBMS_RLS.DROP_POLICY
(
object_schema IN text DEFAULT NULL,
object_name IN text,
policy_name IN text
);CALL dbms_rls.drop_policy
(
object_name => 'employees_rls_test',
policy_name => 'salary_policy'
);DBMS_RLS.ENABLE_POLICY
(
object_schema IN text DEFAULT NULL,
object_name IN text,
policy_name IN text,
enable IN BOOLEAN DEFAULT TRUE
);CALL dbms_rls.enable_policy
(
object_name => 'employees_rls_test',
policy_name => 'context_policy',
enable => true
);DBMS_PIPE.CREATE_PIPE
(
pipename IN TEXT,
maxpipesize IN INTEGER DEFAULT 8192,
private IN BOOLEAN DEFAULT TRUE
)
RETURN INTEGER;SELECT DBMS_PIPE.CREATE_PIPE('tbpipe', 1000, false); DBMS_PIPE.NEXT_ITEM_TYPE()
RETURN PLS_INTEGER;type := DBMS_PIPE.NEXT_ITEM_TYPE;DBMS_PIPE.PACK_MESSAGE (item IN TEXT);
DBMS_PIPE.PACK_MESSAGE (item IN TIMESTAMP);
DBMS_PIPE.PACK_MESSAGE (item IN NUMERIC);
DBMS_PIPE.PACK_MESSAGE (item IN BYTEA);CALL DBMS_PIPE.PACK_MESSAGE('abc');DBMS_PIPE.PURGE
(
pipename IN TEXT
);CALL DBMS_PIPE.PURGE('tbpipe');DBMS_PIPE.RECEIVE_MESSAGE
(
pipename IN TEXT,
timeout IN INTEGER DEFAULT MAXWAIT
)
RETURN INTEGER;status := DBMS_PIPE.RECEIVE_MESSAGE('tbpipe');DBMS_PIPE.REMOVE_PIPE
(
pipename IN TEXT
)
RETURN INTEGER;status := DBMS_PIPE.REMOVE_PIPE('tbpipe'); DBMS_PIPE.RESET_BUFFER();CALL DBMS_PIPE.RESET_BUFFER();DBMS_PIPE.SEND_MESSAGE
(
pipename IN TEXT,
timeout IN INTEGER DEFAULT MAXWAIT,
maxpipesize IN INTEGER DEFAULT 8192
)
RETURN INTEGER;status := DBMS_PIPE.SEND_MESSAGE('tbpipe');DBMS_PIPE.UNIQUE_SESSION_NAME()
RETURN TEXT;text := DBMS_PIPE.UNIQUE_SESSION_NAME();DBMS_PIPE.UNPACK_MESSAGE(item OUT TEXT);
DBMS_PIPE.UNPACK_MESSAGE(item OUT TIMESTAMP);
DBMS_PIPE.UNPACK_MESSAGE(item OUT NUMERIC);
DBMS_PIPE.UNPACK_MESSAGE(item OUT BYTEA);CALL DBMS_PIPE.UNPACK_MESSAGE(msg);NULLCREATE EXTENSION dbms_assert;dbms_assert.enquote_literal(str TEXT) RETURNS TEXTSELECT dbms_assert.enquote_literal('O''''Reilly'); -- [O''Reilly] 라는 문자열을 입력
-- 결과: 'O''''Reilly'
SELECT dbms_assert.enquote_literal('');
-- 결과: ''
SELECT dbms_assert.enquote_literal(NULL);
-- 결과: ''dbms_assert.enquote_name(str TEXT, capitalize BOOLEAN DEFAULT TRUE) RETURNS TEXTSELECT dbms_assert.enquote_name('TableName');
-- 결과: "TABLENAME"
SELECT dbms_assert.enquote_name('TableName', false);
-- 결과: "TableName"
SELECT dbms_assert.enquote_name('');
-- 결과: ""dbms_assert.noop(str TEXT) RETURNS TEXTSELECT dbms_assert.noop('test_input');
-- 결과: 'test_input'
SELECT dbms_assert.noop('');
-- 결과: ''
SELECT dbms_assert.noop(null);
-- 결과: nulldbms_assert.qualified_sql_name(str TEXT) RETURNS TEXT-- 정상 케이스
SELECT dbms_assert.qualified_sql_name('aaa.bbb.ccc."aaaa""aaa"');
-- 결과: aaa.bbb.ccc."aaaa""aaa"
-- 정상 케이스
SELECT dbms_assert.qualified_sql_name('aaa.e$.s_."aa##aa""aaa"');
-- 결과: aaa.e$.s_."aa##aa""aaa"
-- 예외: 특수문자 %
SELECT dbms_assert.qualified_sql_name('aaa.bbb.cc%c."aaaa""aaa"');
-- ERROR: string is not qualified SQL name
-- 예외: 숫자로 시작
SELECT dbms_assert.qualified_sql_name('1broken');
-- ERROR: string is not qualified SQL name
-- 예외: NULL 입력
SELECT dbms_assert.qualified_sql_name(NULL);
-- ERROR: string is not qualified SQL namedbms_assert.schema_name(str TEXT) RETURNS TEXTSELECT dbms_assert.schema_name('pg_catalog'); -- OK
SELECT dbms_assert.schema_name('not_exist_schema'); -- 예외 발생dbms_assert.simple_sql_name(str TEXT) RETURNS TEXT-- 정상 케이스
SELECT dbms_assert.simple_sql_name('"Aaa d$g#h_h shsh"');
-- 결과: "Aaa d$g#h_h shsh"
-- 정상 케이스
SELECT dbms_assert.simple_sql_name('valid_name');
-- 결과: valid_name
-- 정상 케이스
SELECT dbms_assert.simple_sql_name('"as""df"');
-- 결과: "as""df"
-- 예외 발생: 비허용 문자 포함
SELECT dbms_assert.simple_sql_name('ajajaj -- ajaj');
-- ERROR: string is not simple SQL name
-- 예외 발생: 숫자로 시작
SELECT dbms_assert.simple_sql_name('1broken');
-- ERROR: string is not simple SQL name
-- 예외 발생: NULL 입력
SELECT dbms_assert.simple_sql_name(NULL);
-- ERROR: string is not simple SQL namedbms_assert.sql_object_name(str TEXT) RETURNS TEXT-- 존재하는 객체 (대소문자 무관)
SELECT dbms_assert.sql_object_name('pg_catalog.pg_class');
-- 결과: pg_catalog.pg_class
-- 존재하는 객체 (대소문자 무관)
SELECT dbms_assert.sql_object_name('pg_CAtalog.pG_CLaSS');
-- 결과: pg_CAtalog.pG_CLaSS
-- 대소문자 구분 명시 (큰따옴표 사용)
SELECT dbms_assert.sql_object_name('"pg_catalog"."pg_class"');
-- 결과: "pg_catalog"."pg_class"
-- ❌ 예외: 대소문자 틀림
SELECT dbms_assert.sql_object_name('"pg_CAtaLOg"."PG_class"');
-- ERROR: invalid object name
-- ❌ 예외: 존재하지 않는 객체
SELECT dbms_assert.sql_object_name('dbms_assert.fooo');
-- ERROR: invalid object name
-- ❌ 예외: 빈 문자열
SELECT dbms_assert.sql_object_name('');
-- ERROR: invalid object name
-- ❌ 예외: NULL 입력
SELECT dbms_assert.sql_object_name(NULL);
-- ERROR: invalid object nameFCLOSE(file IN UTL_FILE.FILE_TYPE)
RETURNS UTL_FILE.FILE_TYPE;x := UTL_FILE.CLOSE(22);FCLOSE_ALL()
RETURNS VOIDPERFORM UTL_FILE.FCLOSE_ALL();FCOPY(src_location TEXT, src_filename TEXT, dest_location TEXT, dest_filename TEXT)
RETURNS VOID
FCOPY(src_location TEXT, src_filename TEXT, dest_location TEXT, dest_filename TEXT, start_line INTEGER)
RETURNS VOID
FCOPY(src_location TEXT, src_filename TEXT, dest_location TEXT, dest_filename TEXT, start_line INTEGER, end_line INTEGER)
RETURNS VOIDSELECT utl_file.fcopy('test', 'fcopy_test.txt', 'test2', 'fcopy_test2.txt')FFLUSH(file UTL_FILE.FILE_TYPE)
RETURNS VOIDSELECT utl_file.fflush(22);FGETATTR(location TEXT, filename TEXT, OUT fexists BOOLEAN, OUT file_length BIGINT, OUT blocksize INTEGER)SELECT * from utl_file.fgetattr('test', 'fgetattr_test.txt');FOPEN(location TEXT, filename TEXT, open_mode TEXT)
RETURNS UTL_FILE.FILE_TYPE
FOPEN(location TEXT, filename TEXT, open_mode TEXT, max_linesize INTEGER)
RETURNS UTL_FILE.FILE_TYPE
FOPEN(location TEXT, filename TEXT, open_mode TEXT, max_linesize INTEGER, encoding NAME)
RETURNS UTL_FILE.FILE_TYPEX := utl_file.fopen('test/tmp/dir', 'sample.txt', 'r');FREMOVE(location TEXT, filename TEXT)
RETURNS VOIDSELECT utl_file.fremove('test', 'fremove_test.txt');frename(location TEXT, filename TEXT, dest_dir TEXT, dest_file TEXT)
RETURNS VOID
frename(location TEXT, filename TEXT, dest_dir TEXT, dest_file TEXT, overwrite BOOLEAN)
RETURNS VOIDSELECT utl_file.frename('test', 'frename_test.txt', 'test', 'frename_test2.txt', true); get_line(file UTL_FILE.FILE_TYPE, OUT buffer TEXT)
get_line(file UTL_FILE.FILE_TYPE, OUT buffer TEXT, len TEXT)DO
$$
DECLARE
read_file utl_file.file_type;
line TEXT;
len int := 2;
BEGIN
read_file := utl_file.fopen('test', 'read_test.txt', 'r');
SELECT utl_file.get_line(read_file, len) INTO line;
END;
$$;IS_OPEN(file UTL_FILE.FILE_TYPE)DO
$$
DECLARE
read_file utl_file.file_type;
line TEXT;
len int := 2;
BEGIN
read_file := utl_file.fopen('test', 'read_test.txt', 'r');
WHILE utl_file.is_open(read_file)
LOOP
SELECT utl_file.get_line(read_file, len) INTO line;
END LOOP;
END;
$$;NEW_LINE(file UTL_FILE.FILE_TYPE)
RETURNS BOOLEAN
NEW_LINE(file UTL_FILE.FILE_TYPE, lines INTEGER)
RETURNS BOOLEANDO
$$
DECLARE
ftest utl_file.file_type;
pgtap_ok text; -- dummy return for pgtap to work inside anon block
BEGIN
ftest := utl_file.fopen('test', 'put_test.txt', 'w');
-- Put a new line into a txt file
PERFORM utl_file.new_line(ftest);
END;
$$;PUT(file UTL_FILE.FILE_TYPE, buffer TEXT)
RETURNS BOOLEANDO
$$
BEGIN
PERFORM utl_file.put(utl_file.fopen('test', 'put_test.txt', 'w'), 'ABC ');
END;
$$;PUT_LINE(file UTL_FILE.FILE_TYPE, buffer TEXT)
RETURNS BOOLEAN
PUT_LINE(file UTL_FILE.FILE_TYPE, buffer TEXT, autoflush BOOLEAN)
RETURNS BOOLEANDO
$$
BEGIN
PERFORM utl_file.put_line(utl_file.fopen('test', 'put_test.txt', 'w'), 'ABC ', true);
END;
$$;arg1 = 'string1';
arg2 = 'string2';
arg3 = 'string3'; utl_file.putf( ofile, 'This is example of formatted string : %s %s %s \n',
arg1, arg2, arg3);This is example of formated string : string1 string2 string3UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT)
RETURNS BOOLEAN
UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT, arg1 TEXT)
RETURNS BOOLEAN
UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT, arg1 TEXT, arg2 TEXT)
RETURNS BOOLEAN
UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT, arg1 TEXT, arg2 TEXT, arg3 TEXT)
RETURNS BOOLEAN
UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT, arg1 TEXT, arg2 TEXT, arg3 TEXT, arg4 TEXT)
RETURNS BOOLEAN
UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE, format TEXT, arg1 TEXT, arg2 TEXT, arg3 TEXT, arg4 TEXT, arg5 TEXT)
RETURNS BOOLEANDO
$$
BEGIN
PERFORM utl_file.putf(utl_file.fopen('test', 'put_test.txt', 'w'),
'[1=%s, 2=%s, 3=%s, 4=%s, 5=%s]', '1', '2', '3', '4', '5');
END;
$$;CREATE EXTENSION dbms_job;
# 또는 CREATE EXTENSION dbms_job CASCADE; 를 통해 o2scheduler를 동시에 같이 설치합니다.
CALL dbms_job.submit(
OUT job integer,
IN what text,
IN next_date timestamptz DEFAULT CURRENT_TIMESTAMP,
IN "interval" text DEFAULT NULL,
IN no_parse boolean DEFAULT false
)-- 1회 실행(즉시); my_proc 이라는 이름의 프로시져를 지금 당장 실행하는 job을 등록한다.
CALL dbms_job.submit(NULL, 'my_proc');
-- 1시간 주기 반복; my_proc 이라는 이름의 프로시져를 1시간 주기로 반복 실행하는 job을 등록 및 바로 실행한다.
CALL dbms_job.submit(NULL, 'my_proc', "interval" => 'SYSDATE+1/24');
-- 1분 후 첫 실행하고, 이후 매분 반복하는 PL/SQL job을 등록한다.
CALL dbms_job.submit(NULL, 'BEGIN my_proc(); END;',
next_date => now() + interval '1 minute',
"interval" => 'now() + interval ''1'' minute');CALL dbms_job.remove(IN job integer)-- 작업 ID 123 삭제
CALL dbms_job.remove(123);CALL dbms_job.what(IN job integer, IN what text)-- 작업 ID 123의 실행 내용을 다른 프로시저로 변경
CALL dbms_job.what(123, 'my_other_proc');
-- PL/SQL 블록으로 변경
CALL dbms_job.what(123, 'BEGIN my_proc(); my_other_proc(); END;');
CALL dbms_job.run(IN job integer)-- 작업 ID 123 즉시 실행
CALL dbms_job.run(123);
CALL dbms_job.next_date(IN job integer, IN next_date timestamptz)-- 작업 ID 123을 1시간 후에 실행하도록 변경
CALL dbms_job.next_date(123, now() + interval '1 hour');
-- 작업 ID 123의 스케줄링 비활성화
CALL dbms_job.next_date(123, NULL);
CALL dbms_job.interval(IN job integer, IN "interval" text)-- 작업 ID 123을 매일 실행하도록 변경
CALL dbms_job.interval(123, 'SYSDATE+1');
-- 작업 ID 123을 일회성 작업으로 변경
CALL dbms_job.interval(123, NULL);
CALL dbms_job.change(
IN job integer,
IN what text,
IN next_date timestamptz,
IN "interval" text,
IN instance integer DEFAULT 0,
IN "force" boolean DEFAULT false
)-- 작업 ID 123의 실행 내용과 주기를 모두 변경
CALL dbms_job.change(123, 'new_proc', now() + interval '2 hours', 'SYSDATE+1/12');
-- 작업 ID 123의 실행 시각만 변경
CALL dbms_job.change(123, NULL, now() + interval '30 minutes', NULL);
CALL dbms_job.broken(
IN job integer,
IN broken boolean,
IN next_date timestamptz DEFAULT current_timestamp
)-- 작업 ID 123을 깨진 상태로 설정
CALL dbms_job.broken(123, true);
-- 작업 ID 123을 복구하고 1시간 후에 실행하도록 설정
CALL dbms_job.broken(123, false, now() + interval '1 hour');# postgresql.conf
# ...
dbms_job.failure_threshold = 10-- 최근 실행 이력
SELECT * FROM o2scheduler.job_run_details ORDER BY id DESC LIMIT 20;
-- 등록된 잡
SELECT * FROM o2scheduler.job ORDER BY id DESC LIMIT 20;DBMS_JOB, DBMS_SCHEDULER 패키지 사용을 위한 필수 프레임워크 o2 scheduler에 대한 스케쥴러(scheduler) 참조서입니다.
create table src(id numeric, name text, birthdate date);
create table dest as select * from src;
insert into src select i, 'x', current_date from generate_series(1,1000) g(i);
create or replace procedure copy (source in text, dest in text)
as $$
declare
id_var numeric;
name_var text;
birthdate_var date;
source_cursor integer;
destination_cursor integer;
ignore integer;
begin
source_cursor := dbms_sql.open_cursor();
call dbms_sql.parse(source_cursor,
'select id, name, birthdate from ' || source);
call dbms_sql.define_column(source_cursor, 1, id_var);
call dbms_sql.define_column(source_cursor, 2, name_var, 30);
call dbms_sql.define_column(source_cursor, 3, birthdate_var);
perform dbms_sql.execute(source_cursor);
destination_cursor := dbms_sql.open_cursor();
call dbms_sql.parse(destination_cursor,
'insert into ' || dest || ' values (:id_bind, :name_bind, :birthdate_bind)');
loop
if dbms_sql.fetch_rows(source_cursor) > 0 then
call dbms_sql.column_value(source_cursor, 1, id_var);
call dbms_sql.column_value(source_cursor, 2, name_var);
call dbms_sql.column_value(source_cursor, 3, birthdate_var);
call dbms_sql.bind_variable(destination_cursor, ':id_bind', id_var);
call dbms_sql.bind_variable(destination_cursor, ':name_bind', name_var);
call dbms_sql.bind_variable(destination_cursor, ':birthdate_bind', birthdate_var);
ignore := dbms_sql.execute(destination_cursor);
else
exit;
end if;
end loop;
-- Exception절 있을 경우
-- ERROR: cannot commit while a subtransaction is active 발생
commit;
call dbms_sql.close_cursor(source_cursor);
call dbms_sql.close_cursor(destination_cursor);
-- 사용하지 말 것
/*exception
when others then
raise notice 'exception';
if dbms_sql.is_open(source_cursor) then
call dbms_sql.close_cursor(source_cursor);
end if;
if dbms_sql.is_open(destination_cursor) then
call dbms_sql.close_cursor(destination_cursor);
end if;
raise;
*/
end;
$$ language plpgsql; BIND_ARRAY(c INTEGER, name TEXT, value ANYARRAY)
BIND_ARRAY(c INTEGER, name TEXT, value ANYARRAY, index1 INTEGER, index2 INTEGER) DO
$$
DECLARE
c int;
a varchar[];
b int[];
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'insert into foo values(:a, :b)');
a := ARRAY['ahoj1', 'ahoj2', 'ahoj3', 'ahoj4', 'ahoj5'];
b := ARRAY[1, 2, 3, 4, 5];
CALL dbms_sql.bind_array(c, 'a', a, 2, 3);
CALL dbms_sql.bind_array(c, 'b', b, 3, 4);
END;
$$;BIND_VARIABLE(c INTEGER, name TEXT, value "any") DO
$$
DECLARE
c int;
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'insert into test values(:a)');
CALL dbms_sql.bind_variable(c, 'a', 'ahoj');
END;
$$;CLOSE_CURSOR(c INTEGER)DO
$$
DECLARE
c int;
BEGIN
c := dbms_sql.open_cursor();
call dbms_sql.close_cursor();
END;
$$;DEFINE_COLUMN(c INTEGER, pos INTEGER, INOUT value anyelement) DO
$$
DECLARE
c int;
strval varchar;
intval int;
stack text := '';
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_column(c, 1, strval);
CALL dbms_sql.define_column(c, 2, intval);
PERFORM dbms_sql.execute(c);
WHILE dbms_sql.fetch_rows(c) > 0
LOOP
CALL dbms_sql.column_value(c, 1, strval);
CALL dbms_sql.column_value(c, 2, intval);
END LOOP;
CALL dbms_sql.close_cursor(c);
END;
$$;DEFINE_COLUMN(c INTEGER, col INTEGER, value "any", column_size INTEGER) DO
$$
DECLARE
c int;
strval varchar;
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''test'', i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_column(c, 1, strval);
END;
$$;DEFINE_ARRAY(c INTEGER, col INTEGER, value "anyarray", cnt INTEGER, lower_bnd INTEGER) DO
$$
DECLARE
c int;
strval varchar[];
intval int[];
stack text := '';
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_array(c, 1, strval, 5, 1);
CALL dbms_sql.define_array(c, 2, intval, 5, 1);
END;
$$;EXECUTE(c IN INTEGER)
RETURNS BIGINTDO
$$
DECLARE
c int;
a varchar[];
b int[];
result int;
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'insert into foo values(:a, :b)');
a := ARRAY['ahoj1', 'ahoj2', 'ahoj3', 'ahoj4', 'ahoj5'];
b := ARRAY[1, 2, 3, 4, 5];
CALL dbms_sql.bind_array(c, 'a', a, 2, 3);
CALL dbms_sql.bind_array(c, 'b', b, 3, 4);
result := dbms_sql.execute(c);
CALL dbms_sql.close_cursor(c);
END;
$$;EXECUTE_AND_FETCH(c IN INTEGER, exact IN BOOL)
RETURNS INTDO
$$
DECLARE
c int;
strval varchar;
intval int;
stack text := '';
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_column(c, 1, strval);
CALL dbms_sql.define_column(c, 2, intval);
PERFORM dbms_sql.execute_and_fetch(c, false);
WHILE dbms_sql.fetch_rows(c) > 0
LOOP
CALL dbms_sql.column_value(c, 1, strval);
CALL dbms_sql.column_value(c, 2, intval);
END LOOP;
CALL dbms_sql.close_cursor(c);
END;
$$;FETCH_ROWS(c IN INTEGER)
RETURNS INTEGERDO
$$
DECLARE
c int;
strval varchar;
intval int;
stack text := '';
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_column(c, 1, strval);
CALL dbms_sql.define_column(c, 2, intval);
PERFORM dbms_sql.execute(c);
WHILE dbms_sql.fetch_rows(c) > 0
LOOP
CALL dbms_sql.column_value(c, 1, strval);
CALL dbms_sql.column_value(c, 2, intval);
END LOOP;
CALL dbms_sql.close_cursor(c);
END;
$$;IS_OPEN(c IN INTEGER)
RETURNS BOOLDO
$$
DECLARE
c int;
x bool;
BEGIN
c := dbms_sql.open_cursor();
x := dbms_sql.is_open(c);
END;
$$;LAST_ROW_COUNT()
RETURNS INTDO
$$
DECLARE
c int;
strval varchar;
intval int;
n int;
BEGIN
c := dbms_sql.open_cursor();
CALL dbms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, 5) g(i)');
CALL dbms_sql.define_column(c, 1, strval);
CALL dbms_sql.define_column(c, 2, intval);
PERFORM dbms_sql.execute(c);
WHILE dbms_sql.fetch_rows(c) > 0
LOOP
CALL dbms_sql.column_value(c, 1, strval);
CALL dbms_sql.column_value(c, 2, intval);
n := dbms_sql.last_row_count();
END LOOP;
CALL dbms_sql.close_cursor(c);
END;
$$;OPEN_CURSOR()
RETURNS INTEGERDO
$$
DECLARE
c int;
BEGIN
c := dbms_sql.open_cursor();
END;
$$;PARSE(c INTEGER, stmt TEXT)DO
$$
DECLARE
c int;
BEGIN
c := dbms_sql.open_cursor();
call dbms_sql.parse(c, 'insert into test values(''test1'',1)');
END;
$$;postgresql.conf 파일 내부 내용 중
...
#shared_preload_libraries = '' # (change requires restart) <= 이 라인을 아래와 같이 수정합니다.
shared_preload_libraries = 'o2scheduler'
(이때, 라인의 맨 앞 '#' 문자도 반드시 제거해줍니다.)shared_preload_libraries = 'a,b' <- 이미 a,b extension들이 추가되어있을 경우, 이어서 o2scheduler를 추가합니다.
=> shared_preload_libraries = 'a,b,o2scheduler'postgresql.conf 파일 내부 내용 중
...
#max_worker_processes = 8 # (change requires restart) <= 이 라인을 아래와 같이 수정합니다.
max_worker_processes = {원하는 숫자}
(이때, 라인의 맨 앞 '#' 문자도 반드시 제거해줍니다)create extension o2scheduler;root=# create extension o2scheduler;
CREATE EXTENSION
root=# \dx
List of installed extensions
Name | Version | Schema | Description
-------------+---------+------------+--------------------------------------------------------------
o2scheduler | 1.0 | public | Provides scheduler functions compatible with Oracle database
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
(2 rows)CREATE_JOB(
IN job_name TEXT,
IN job_type TEXT,
IN job_action TEXT,
IN number_of_arguments INTEGER DEFAULT 0,
IN start_date TIMESTAMPTZ DEFAULT NULL,
IN repeat_interval TEXT DEFAULT NULL,
IN end_date TIMESTAMPTZ DEFAULT NULL,
IN job_class TEXT DEFAULT 'DEFAULT_JOB_CLASS',
IN enabled BOOLEAN DEFAULT FALSE,
IN auto_drop BOOLEAN DEFAULT TRUE,
IN comments TEXT DEFAULT NULL
)
CREATE_JOB(
IN job_name TEXT,
IN program_name TEXT,
IN schedule_name TEXT,
IN job_class TEXT DEFAULT 'DEFAULT_JOB_CLASS',
IN enabled BOOLEAN DEFAULT FALSE,
IN auto_drop BOBOLEAN DEFAULT TRUE,
IN comments TEXT DEFAULT NULL
)CALL dbms_scheduler.create_job(job_name => 'job1',
job_type => 'plsql_block',
job_action => 'DO $test$ BEGIN SELECT * FROM nonexistent_table; END; $test$;',
number_of_arguments => 0,
start_date => now(),
repeat_interval => 'FREQ=DAILY',
end_date => now() + interval '10 days',
enabled => true,
auto_drop => true);
CALL dbms_scheduler.create_job(job_name => 'job2',
program_name => 'program1',
schedule_name => 'schedule1',
enabled => true,
auto_drop => true);CREATE_PROGRAM(
IN program_name TEXT,
IN program_type TEXT,
IN program_action TEXT,
IN nargs INTEGER DEFAULT 0,
IN enabled IN BOOLEAN DEFAULT FALSE,
IN comments In TEXT DEFAULT NULL
)CALL dbms_scheduler.CREATE_PROGRAM('program1', 'STORED_PROCEDURE', 'procedure1', 0, true, NULL);
CALL dbms_scheduler.CREATE_PROGRAM(
program_name => 'program1',
program_type => 'stored_procedure',
program_action => 'procedure1',
nargs => 0,
enabled => true,
comments => NULL
); CREATE_SCHEDULE(
IN schedule_name TEXT,
IN repeat_interval TEXT,
IN start_date TIMESTAMPTZ DEFAULT NULL,
IN end_date TIMESTAMPTZ DEFAULT NULL,
IN comments TEXT DEFAULT NULL
)CALL dbms_scheduler.CREATE_SCHEDULE('schedule1', 'FREQ=DAILY', now(), now()+'10 days'::interval, NULL);DEFINE_PROGRAM_ARGUMENT(
IN program_name TEXT,
IN argument_position INTEGER,
IN argument_type TEXT,
IN default_value TEXT,
IN argument_name TEXT DEFAULT NULL,
IN out_argument BOOLEAN DEFAULT FALSE
)
DEFINE_PROGRAM_ARGUMENT(
IN program_name TEXT,
IN argument_position INTEGER,
IN argument_type TEXT,
IN argument_name TEXT DEFAULT NULL,
IN out_argument BOOLEAN DEFAULT FALSE
)CALL dbms_scheduler.DEFINE_PROGRAM_ARGUMENT(
'program_1args',
1,
'text',
'default_value',
'arg1', false
);
CALL dbms_scheduler.DEFINE_PROGRAM_ARGUMENT(
'program2',
2,
'integer',
'arg2',
false
);DISABLE(
IN name TEXT,
IN force BOOLEAN DEFAULT FALSE,
IN commit_syntax TEXT DEFAULT 'STOP_ON_FIRST_ERROR'
)CALL dbms_scheduler.DISABLE('program1', false, STOP_ON_FIRST_ERROR');DROP_JOB(
IN job_name TEXT,
IN force BOOLEAN DEFAULT FALSE,
IN defer BOOLEAN DEFAULT FALSE,
IN commit_semantics TEXT DEFAULT 'STOP_ON_FIRST_ERROR'
)CALL dbms_scheduler.DROP_JOB('job1', true, false, 'STOP_ON_FIRST_ERROR');DROP_PROGRAM(
IN program_name TEXT,
IN force BOOLEAN DEFAULT FALSE
)CALL dbms_scheduler.DROP_PROGRAM('drop_program', true);DROP_PROGRAM_ARGUMENT(
IN program_name TEXT,
IN argument_position TEXT
)
DROP_PROGRAM_ARGUMENT(
IN program_name TEXT,
IN argument_name TEXT
)CALL dbms_scheduler.DROP_PROGRAM_ARGUMENT('program1', 1);
CALL dbms_scheduler.DROP_PROGRAM_ARGUMENT('program1', 'old');DROP_SCHEDULE(
IN schedule_name TEXT,
IN force BOOLEAN DEFAULT FALSE
)CALL dbms_scheduler.DROP_SCHEDULE('schedule1', true);ENABLE(
IN name TEXT,
IN commit_semantics TEXT DEFAULT 'STOP_ON_FIRST_ERROR'
)CALL dbms_scheduler.ENABLE('program1');EVALUATE_CALENDAR_STRING(
IN expr TEXT,
IN start_date TIMESTAMPTZ,
IN return_date_after TIMESTAMPTZ,
OUT next_run_date TIMESTAMPTZ
)DO $$
DECLARE
result TIMESTAMP WITH TIME ZONE;
BEGIN
CALL DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING
(
'FREQ=DAILY;BYDAY=MON,TUE,WED,THU,FRI;BYHOUR=17;',
'15-JUN-2013', NULL, result
);
CALL DBMS_OUTPUT.PUT_LINE('next_run_date: ' || result);
END;
$$;
DO $$
DECLARE
result TIMESTAMP WITH TIME ZONE;
BEGIN
CALL dbms_scheduler.evaluate_calendar_string(
expr => 'FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=29',
start_date => TIMESTAMPTZ '2024-01-01 00:00:00+09',
return_date_after => TIMESTAMPTZ '2024-12-31 23:59:59+09',
result => result
);
raise notice 'date: %', result;
END;
$$;RUN_JOB(
IN job_name TEXT,
IN use_current_session BOOLEAN DEFAULT TRUE
)DBMS_SCHEDULER.RUN_JOB('job1', TRUE);SET_JOB_ARGUMENT_VALUE(
IN job_name TEXT,
IN argument_position INTEGER,
IN argument_value TEXT
)
SET_JOB_ARGUMENT_VALUE(
IN job_name TEXT,
IN argument_name TEXT,
IN argument_value TEXT
)CALL dbms_scheduler.SET_JOB_ARGUMENT_VALUE('job1', 1, '30');
CALL dbms_scheduler.SET_JOB_ARGUMENT_VALUE('job1', 'arg1', 'SMITH');뷰에 대한 참조 안내서입니다.
{schema_name}.{view_name}
-- 예시) o2views extension 설치 후, 새로 추가된 dba_tab_columns라는 뷰 사용합니다.
-- select * from oracle.dba_tab_columns;
-- 현재 접속 세션에서 스미카 'oracle'를 가장 우선순위 높은 search_path로 설정합니다.
set search_path to oracle, public;
{view_name}
-- 예시) o2views extension 설치 후, 새로 추가된 dba_tab_columns라는 뷰 사용합니다.
-- select * from dba_tab_columns;