DROP TABLE sales_history PURGE;
CREATE TABLE sales_history (
id NUMBER,
product VARCHAR2(20),
tstamp TIMESTAMP,
units_sold NUMBER,
CONSTRAINT sales_history_pk PRIMARY KEY (id)
);
ALTER SESSION SET nls_timestamp_format = 'DD-MON-YYYY';
INSERT INTO sales_history VALUES ( 1, 'TWINKIES', '01-OCT-2014', 17);
INSERT INTO sales_history VALUES ( 2, 'TWINKIES', '02-OCT-2014', 19);
INSERT INTO sales_history VALUES ( 3, 'TWINKIES', '03-OCT-2014', 23);
INSERT INTO sales_history VALUES ( 4, 'TWINKIES', '04-OCT-2014', 23);
INSERT INTO sales_history VALUES ( 5, 'TWINKIES', '05-OCT-2014', 16);
INSERT INTO sales_history VALUES ( 6, 'TWINKIES', '06-OCT-2014', 10);
INSERT INTO sales_history VALUES ( 7, 'TWINKIES', '07-OCT-2014', 14);
INSERT INTO sales_history VALUES ( 8, 'TWINKIES', '08-OCT-2014', 16);
INSERT INTO sales_history VALUES ( 9, 'TWINKIES', '09-OCT-2014', 15);
INSERT INTO sales_history VALUES (10, 'TWINKIES', '10-OCT-2014', 17);
INSERT INTO sales_history VALUES (11, 'TWINKIES', '11-OCT-2014', 23);
INSERT INTO sales_history VALUES (12, 'TWINKIES', '12-OCT-2014', 30);
INSERT INTO sales_history VALUES (13, 'TWINKIES', '13-OCT-2014', 31);
INSERT INTO sales_history VALUES (14, 'TWINKIES', '14-OCT-2014', 29);
INSERT INTO sales_history VALUES (15, 'TWINKIES', '15-OCT-2014', 25);
INSERT INTO sales_history VALUES (16, 'TWINKIES', '16-OCT-2014', 21);
INSERT INTO sales_history VALUES (17, 'TWINKIES', '17-OCT-2014', 35);
INSERT INTO sales_history VALUES (18, 'TWINKIES', '18-OCT-2014', 46);
INSERT INTO sales_history VALUES (19, 'TWINKIES', '19-OCT-2014', 45);
INSERT INTO sales_history VALUES (20, 'TWINKIES', '20-OCT-2014', 30);
COMMIT;
-- 한국인 입장으로 다시 표기
ALTER SESSION SET nls_timestamp_format = 'YYYY-MM-DD';
SET PAGESIZE 50
COLUMN product FORMAT A10
COLUMN tstamp FORMAT A11
COLUMN graph FORMAT A50
-- 데이터를 출력한다.
SELECT id,
product,
tstamp,
units_sold,
RPAD('#', units_sold, '#') AS graph
FROM sales_history
ORDER BY id;
ID PRODUCT TSTAMP UNITS_SOLD GRAPH
---------- ---------- ----------- ---------- --------------------------------------------------
1 TWINKIES 2014-10-01 17 #################
2 TWINKIES 2014-10-02 19 ###################
3 TWINKIES 2014-10-03 23 #######################
4 TWINKIES 2014-10-04 23 #######################
5 TWINKIES 2014-10-05 16 ################
6 TWINKIES 2014-10-06 10 ##########
7 TWINKIES 2014-10-07 14 ##############
8 TWINKIES 2014-10-08 16 ################
9 TWINKIES 2014-10-09 15 ###############
10 TWINKIES 2014-10-10 17 #################
11 TWINKIES 2014-10-11 23 #######################
12 TWINKIES 2014-10-12 30 ##############################
13 TWINKIES 2014-10-13 31 ###############################
14 TWINKIES 2014-10-14 29 #############################
15 TWINKIES 2014-10-15 25 #########################
16 TWINKIES 2014-10-16 21 #####################
17 TWINKIES 2014-10-17 35 ###################################
18 TWINKIES 2014-10-18 46 ##############################################
19 TWINKIES 2014-10-19 45 #############################################
20 TWINKIES 2014-10-20 30 ##############################
20 rows selected.
COLUMN start_tstamp FORMAT A11
COLUMN peak_tstamp FORMAT A11
COLUMN end_tstamp FORMAT A11
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product -- 데이터의 그룹화 과정, 여기서는 product 별로 패턴을 찾기로 함
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp, -- 패턴매칭으로 가져올 컬럼명을 새로 지정함
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno -- 패턴을 만족한 개수
ONE ROW PER MATCH -- 패턴을 만족하는 ROW 1개만 보여줌(중복제거 효과), ALL ROWS : 패턴을 만족하는 과정의 모든 ROW를 보여줌
AFTER MATCH SKIP TO LAST DOWN -- 현재 패턴을 만족 하는 마지막 DOWN 시작점부터 다시 패턴을 찾기 시작함
PATTERN (STRT UP+ FLAT* DOWN+) -- 패턴을 정의 : UP이 1개 이상, FLAT은 0개 이상, DOWN은 1개 이상인 경우
DEFINE -- 패턴의 변수를 정의 : STRT의 경우 하단에 정의하지 않았으므로 모든 row에 매칭된다.
UP AS UP.units_sold > PREV(UP.units_sold), -- UP : 이전 units_sold 보다 큰 경우
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold), -- FLAT : 이전 units_sold와 같은 경우
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold) -- DOWN : 이전 units_sold와 작은 경우
) MR
ORDER BY MR.product, MR.start_tstamp;
PRODUCT START_TSTAM PEAK_TSTAMP END_TSTAMP MNO
---------- ----------- ----------- ----------- ----------
TWINKIES 01-OCT-2014 03-OCT-2014 06-OCT-2014 1
TWINKIES 06-OCT-2014 08-OCT-2014 09-OCT-2014 2
TWINKIES 09-OCT-2014 13-OCT-2014 16-OCT-2014 3
TWINKIES 16-OCT-2014 18-OCT-2014 20-OCT-2014 4
4 rows selected.
-- ONE ROW PER MATCH를 ALL ROWS PER MATCH로 변경
COLUMN start_tstamp FORMAT A11
COLUMN peak_tstamp FORMAT A11
COLUMN end_tstamp FORMAT A11
COLUMN final_peak_tstamp FORMAT A11
COLUMN final_end_tstamp FORMAT A11
COLUMN cls FORMAT A5
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
FINAL LAST(UP.tstamp) AS final_peak_tstamp, -- Final : 가장 마지막 패턴 매칭값이 나옴
FINAL LAST(DOWN.tstamp) AS final_end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls -- 분류자(패턴 정의시 사용한 변수)
ALL ROWS PER MATCH -- 패턴을 만족하는 모든 ROW가 나타남
AFTER MATCH SKIP TO LAST DOWN
PATTERN (STRT UP+ FLAT* DOWN+)
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold),
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold)
) MR
ORDER BY MR.product, MR.mno, MR.tstamp;
PRODUCT TSTAMP START_TSTAM PEAK_TSTAMP END_TSTAMP FINAL_PEAK_ FINAL_END_T MNO CLS ID UNITS_SOLD
---------- -------------------- ----------- ----------- ----------- ----------- ----------- ---------- ----- ---------- ----------
TWINKIES 2014-10-01 2014-10-01 2014-10-03 2014-10-06 1 STRT 1 17
TWINKIES 2014-10-02 2014-10-01 2014-10-02 2014-10-03 2014-10-06 1 UP 2 19
TWINKIES 2014-10-03 2014-10-01 2014-10-03 2014-10-03 2014-10-06 1 UP 3 23
TWINKIES 2014-10-04 2014-10-01 2014-10-03 2014-10-03 2014-10-06 1 FLAT 4 23
TWINKIES 2014-10-05 2014-10-01 2014-10-03 2014-10-05 2014-10-03 2014-10-06 1 DOWN 5 16
TWINKIES 2014-10-06 2014-10-01 2014-10-03 2014-10-06 2014-10-03 2014-10-06 1 DOWN 6 10
TWINKIES 2014-10-07 2014-10-07 2014-10-08 2014-10-09 2 STRT 7 14
TWINKIES 2014-10-08 2014-10-07 2014-10-08 2014-10-08 2014-10-09 2 UP 8 16
TWINKIES 2014-10-09 2014-10-07 2014-10-08 2014-10-09 2014-10-08 2014-10-09 2 DOWN 9 15
TWINKIES 2014-10-10 2014-10-10 2014-10-13 2014-10-16 3 STRT 10 17
TWINKIES 2014-10-11 2014-10-10 2014-10-11 2014-10-13 2014-10-16 3 UP 11 23
TWINKIES 2014-10-12 2014-10-10 2014-10-12 2014-10-13 2014-10-16 3 UP 12 30
TWINKIES 2014-10-13 2014-10-10 2014-10-13 2014-10-13 2014-10-16 3 UP 13 31
TWINKIES 2014-10-14 2014-10-10 2014-10-13 2014-10-14 2014-10-13 2014-10-16 3 DOWN 14 29
TWINKIES 2014-10-15 2014-10-10 2014-10-13 2014-10-15 2014-10-13 2014-10-16 3 DOWN 15 25
TWINKIES 2014-10-16 2014-10-10 2014-10-13 2014-10-16 2014-10-13 2014-10-16 3 DOWN 16 21
TWINKIES 2014-10-17 2014-10-17 2014-10-18 2014-10-20 4 STRT 17 35
TWINKIES 2014-10-18 2014-10-17 2014-10-18 2014-10-18 2014-10-20 4 UP 18 46
TWINKIES 2014-10-19 2014-10-17 2014-10-18 2014-10-19 2014-10-18 2014-10-20 4 DOWN 19 45
TWINKIES 2014-10-20 2014-10-17 2014-10-18 2014-10-20 2014-10-18 2014-10-20 4 DOWN 20 30
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
FINAL LAST(UP.tstamp) AS peak_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST DOWN
PATTERN (STRT UP+ DOWN{1} UP+) -- 패턴 : UP 1회 이상, DOWN 1회, UP 1회 이상
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold)
) MR
ORDER BY MR.product, MR.tstamp;
PRODUCT TSTAMP START_TSTAM PEAK_TSTAMP MNO CLS ID UNITS_SOLD
---------- -------------------- ----------- ----------- ---------- ----- ---------- ----------
TWINKIES 2014-10-06 2014-10-06 2014-10-13 1 STRT 6 10
TWINKIES 2014-10-07 2014-10-06 2014-10-13 1 UP 7 14
TWINKIES 2014-10-08 2014-10-06 2014-10-13 1 UP 8 16
TWINKIES 2014-10-09 2014-10-06 2014-10-13 1 DOWN 9 15
TWINKIES 2014-10-10 2014-10-06 2014-10-13 1 UP 10 17
TWINKIES 2014-10-11 2014-10-06 2014-10-13 1 UP 11 23
TWINKIES 2014-10-12 2014-10-06 2014-10-13 1 UP 12 30
TWINKIES 2014-10-13 2014-10-06 2014-10-13 1 UP 13 31
8 rows selected.
-- 패턴 매칭을 시작점을 정의
-- AFTER MATCH SKIP TO NEXT ROW : 패턴을 만족시키는 ROW 바로 뒤 ROW부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP PAST LAST ROW : 현재 패턴을 만족시키는 마지막 ROW 부터 패턴매칭을 다시 시작함
-- AFTER MATCH SKIP TO FIRST pattern_variable : 첫번째 pattern_variable 부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP TO LAST pattern_variable : 마지막 pattern_variable 부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP TO pattern_variable : AFTER MATCH SKIP TO LAST pattern_variable 와 동일 기능
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno
ONE ROW PER MATCH
AFTER MATCH SKIP TO NEXT ROW -- 패턴을 만족시키는 ROW 바로 뒤 ROW부터 다시 패턴매칭을 시작함
PATTERN (STRT UP+ FLAT* DOWN+)
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold)
) MR
ORDER BY MR.product, MR.start_tstamp;
PRODUCT START_TSTAM PEAK_TSTAMP END_TSTAMP MNO
---------- ----------- ----------- ----------- ----------
TWINKIES 2014-10-01 2014-10-03 2014-10-06 1
TWINKIES 2014-10-02 2014-10-03 2014-10-06 2
TWINKIES 2014-10-06 2014-10-08 2014-10-09 3
TWINKIES 2014-10-07 2014-10-08 2014-10-09 4
TWINKIES 2014-10-09 2014-10-13 2014-10-16 5
TWINKIES 2014-10-10 2014-10-13 2014-10-16 6
TWINKIES 2014-10-11 2014-10-13 2014-10-16 7
TWINKIES 2014-10-12 2014-10-13 2014-10-16 8
TWINKIES 2014-10-16 2014-10-18 2014-10-20 9
TWINKIES 2014-10-17 2014-10-18 2014-10-20 10
10 rows selected.
-- 새로운 형태의 데이터 생성
CREATE TABLE sales_audit (
id NUMBER,
product VARCHAR2(20),
tstamp TIMESTAMP,
CONSTRAINT sales_audit_pk PRIMARY KEY (id)
);
ALTER SESSION SET nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS';
INSERT INTO sales_audit VALUES ( 1, 'TWINKIES', '01-OCT-2014 12:00:01');
INSERT INTO sales_audit VALUES ( 2, 'TWINKIES', '01-OCT-2014 12:00:02');
INSERT INTO sales_audit VALUES ( 3, 'DINGDONGS', '01-OCT-2014 12:00:03');
INSERT INTO sales_audit VALUES ( 4, 'HOHOS', '01-OCT-2014 12:00:04');
INSERT INTO sales_audit VALUES ( 5, 'HOHOS', '01-OCT-2014 12:00:05');
INSERT INTO sales_audit VALUES ( 6, 'TWINKIES', '01-OCT-2014 12:00:06');
INSERT INTO sales_audit VALUES ( 7, 'TWINKIES', '01-OCT-2014 12:00:07');
INSERT INTO sales_audit VALUES ( 8, 'DINGDONGS', '01-OCT-2014 12:00:08');
INSERT INTO sales_audit VALUES ( 9, 'DINGDONGS', '01-OCT-2014 12:00:09');
INSERT INTO sales_audit VALUES (10, 'HOHOS', '01-OCT-2014 12:00:10');
INSERT INTO sales_audit VALUES (11, 'HOHOS', '01-OCT-2014 12:00:11');
INSERT INTO sales_audit VALUES (12, 'TWINKIES', '01-OCT-2014 12:00:12');
INSERT INTO sales_audit VALUES (13, 'TWINKIES', '01-OCT-2014 12:00:13');
INSERT INTO sales_audit VALUES (14, 'DINGDONGS', '01-OCT-2014 12:00:14');
INSERT INTO sales_audit VALUES (15, 'DINGDONGS', '01-OCT-2014 12:00:15');
INSERT INTO sales_audit VALUES (16, 'HOHOS', '01-OCT-2014 12:00:16');
INSERT INTO sales_audit VALUES (17, 'TWINKIES', '01-OCT-2014 12:00:17');
INSERT INTO sales_audit VALUES (18, 'TWINKIES', '01-OCT-2014 12:00:18');
INSERT INTO sales_audit VALUES (19, 'TWINKIES', '01-OCT-2014 12:00:19');
INSERT INTO sales_audit VALUES (20, 'TWINKIES', '01-OCT-2014 12:00:20');
COMMIT;
COLUMN tstamp FORMAT A20
COLUMN start_tstamp FORMAT A20
COLUMN end_tstamp FORMAT A20
COLUMN cls FORMAT A10
SELECT *
FROM sales_audit MATCH_RECOGNIZE (
--PARTITION BY product -- 생략 가능함
ORDER BY tstamp -- 생략 가능함
MEASURES FIRST(TWINKIES.tstamp) AS start_tstamp,
FINAL LAST(TWINKIES.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST TWINKIES
PATTERN(TWINKIES{2,} DINGDONGS{2} HOHOS{1} TWINKIES{3,}) -- TWINKIES가 2번 이상, DINGDONGS가 2번, HOHOS가 1번, TWINKIES가 3번 이상
DEFINE
TWINKIES AS TWINKIES.product='TWINKIES',
DINGDONGS AS DINGDONGS.product='DINGDONGS',
HOHOS AS HOHOS.product='HOHOS'
) MR
ORDER BY MR.mno, MR.tstamp;
TSTAMP START_TSTAMP END_TSTAMP MNO CLS ID PRODUCT
-------------------- -------------------- -------------------- ---------- ---------- ---------- ----------
2014-10-01 12:00:12 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 12 TWINKIES
2014-10-01 12:00:13 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 13 TWINKIES
2014-10-01 12:00:14 2014-10-01 12:00:12 2014-10-01 12:00:20 1 DINGDONGS 14 DINGDONGS
2014-10-01 12:00:15 2014-10-01 12:00:12 2014-10-01 12:00:20 1 DINGDONGS 15 DINGDONGS
2014-10-01 12:00:16 2014-10-01 12:00:12 2014-10-01 12:00:20 1 HOHOS 16 HOHOS
2014-10-01 12:00:17 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 17 TWINKIES
2014-10-01 12:00:18 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 18 TWINKIES
2014-10-01 12:00:19 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 19 TWINKIES
2014-10-01 12:00:20 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 20 TWINKIES
SELECT *
FROM sales_audit MATCH_RECOGNIZE (
--PARTITION BY product
ORDER BY tstamp
MEASURES FIRST(TWINKIES.tstamp) AS start_tstamp,
FINAL LAST(TWINKIES.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST TWINKIES
PATTERN(TWINKIES+ (DINGDONGS | HOHOS){3} TWINKIES+) -- TWINKIES 1번 이상, DINGDONGS 또는 HOHOS가 3회, TWINKIES 가 1회 이상
DEFINE
TWINKIES AS TWINKIES.product='TWINKIES',
DINGDONGS AS DINGDONGS.product='DINGDONGS',
HOHOS AS HOHOS.product='HOHOS'
) MR
ORDER BY MR.mno, MR.tstamp;
TSTAMP START_TSTAMP END_TSTAMP MNO CLS ID PRODUCT
-------------------- -------------------- -------------------- ---------- ---------- ---------- ----------
2014-10-01 12:00:01 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 1 TWINKIES
2014-10-01 12:00:02 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 2 TWINKIES
2014-10-01 12:00:03 2014-10-01 12:00:01 2014-10-01 12:00:07 1 DINGDONGS 3 DINGDONGS
2014-10-01 12:00:04 2014-10-01 12:00:01 2014-10-01 12:00:07 1 HOHOS 4 HOHOS
2014-10-01 12:00:05 2014-10-01 12:00:01 2014-10-01 12:00:07 1 HOHOS 5 HOHOS
2014-10-01 12:00:06 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 6 TWINKIES
2014-10-01 12:00:07 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 7 TWINKIES
2014-10-01 12:00:12 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 12 TWINKIES
2014-10-01 12:00:13 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 13 TWINKIES
2014-10-01 12:00:14 2014-10-01 12:00:12 2014-10-01 12:00:20 2 DINGDONGS 14 DINGDONGS
2014-10-01 12:00:15 2014-10-01 12:00:12 2014-10-01 12:00:20 2 DINGDONGS 15 DINGDONGS
2014-10-01 12:00:16 2014-10-01 12:00:12 2014-10-01 12:00:20 2 HOHOS 16 HOHOS
2014-10-01 12:00:17 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 17 TWINKIES
2014-10-01 12:00:18 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 18 TWINKIES
2014-10-01 12:00:19 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 19 TWINKIES
2014-10-01 12:00:20 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 20 TWINKIES
16 rows selected.
-- 11g에서 실행할 경우 에러가 발생
SELECT COUNT(*)
FROM SCOTT.EMP A, SCOTT.DEPT B, SCOTT.BONUS C
WHERE B.DEPTNO = A.DEPTNO(+)
AND C.ENAME = A.ENAME(+);
ERROR AT LINE 3:
ORA-01417: a tabe may be outer joined to at most one other table
-- 12c에서는 오류 없이 쿼리가 실행된다.
SELECT COUNT(*)
FROM SCOTT.EMP A, SCOTT.DEPT B, SCOTT.BONUS C
WHERE B.DEPTNO = A.DEPTNO(+)
AND C.ENAME = A.ENAME(+);
COUNT(*)
----------
0
실행계획 :
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | 7 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 | | |
|* 2 | HASH JOIN OUTER | | 1 | 40 | 7 (0)| 00:00:01 |
| 3 | MERGE JOIN CARTESIAN | | 1 | 20 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | BONUS | 1 | 7 | 2 (0)| 00:00:01 |
| 5 | BUFFER SORT | | 4 | 52 | 2 (0)| 00:00:01 |
| 6 | INDEX FAST FULL SCAN| PK_DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | EMP | 14 | 280 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------
select count(*) from emp;
COUNT(*)
----------
14
select empno, hiredate from emp order by hiredate asc;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
7902 1981-12-03 00:00:00
7934 1982-01-23 00:00:00
7788 1987-04-19 00:00:00
7876 1987-05-23 00:00:00
14 rows selected.
-- 8번째 row를 건너뛰고 조회됨
select empno, hiredate from emp order by hiredate offset 8 rows;
EMPNO HIREDATE
---------- -------------------
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
7902 1981-12-03 00:00:00
7934 1982-01-23 00:00:00
7788 1987-04-19 00:00:00
7876 1987-05-23 00:00:00
6 rows selected.
-- 10개의 row를 가져옴
select empno, hiredate from emp
order by hiredate fetch first 10 rows only;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
10 rows selected.
-- 25%만큼의 데이터만 가져옴
select empno, hiredate from emp
order by hiredate fetch first 25 percent rows only;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
select empno, hiredate from emp
order by hiredate fetch next 25 percent rows only; -- first / next는 서로 동일한 기능을 하였다.
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
-- 4개의 row를 건너뛰고, 5번째 row부터 25% 가져옴
select empno, hiredate from emp
order by hiredate offset 4 rows fetch next 25 percent rows only;
EMPNO HIREDATE
---------- -------------------
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
-- with ties절은 마지막 row가 서로 동률일 경우 동률인 row를 모두 가져옴
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary
FETCH FIRST 5 PERCENT ROWS ONLY;
EMPLOYEE_ID LAST_NAME SALARY
----------- ------------------------- ----------
132 Olson 2100
128 Markle 2200
136 Philtanker 2200
127 Landry 2400
135 Gee 2400
119 Colmenares 2500
6 rows selected.
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary
FETCH FIRST 5 PERCENT ROWS WITH TIES;
EMPLOYEE_ID LAST_NAME SALARY
----------- ------------------------- ----------
132 Olson 2100
128 Markle 2200
136 Philtanker 2200
127 Landry 2400
135 Gee 2400
119 Colmenares 2500
131 Marlow 2500
140 Patel 2500
144 Vargas 2500
182 Sullivan 2500
191 Perkins 2500
11 rows selected.
create table big_table
as
select object_id, object_name
from (select object_id, object_name from dba_objects where rownum <=1000) a
, (select level from dual connect by level <= 1000) b
;
create index big_table_idx1 on big_table(object_id asc);
analyze table big_table compute statistics;
select count(*) cnt from big_table where object_id = 885;
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
------------------------------------------------------------------------------------
select count(*) cnt from big_table where object_id = 885
union all
select count(*) cnt from big_table where object_id = 237
union all
select count(*) cnt from big_table where object_id = 420
union all
select count(*) cnt from big_table where object_id = 557
union all
select count(*) cnt from big_table where object_id = 880
;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 6 | 10 (0)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
| 2 | SORT AGGREGATE | | 1 | 3 | | |
|* 3 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 3 | | |
|* 5 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select name, value from v$parameter where name = 'max_string_size';
NAME VALUE
---------------- ----------------
max_string_size STANDARD
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001));
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001))
*
ERROR at line 1:
ORA-00910: specified length too long for its datatype
CONN / AS SYSDBA
SHUTDOWN IMMEDIATE;
STARTUP UPGRADE;
ALTER SYSTEM SET max_string_size=extended;
@?/rdbms/admin/utl32k.sql -- recyclebin에 테이블이 있을 경우 에러발생, recyclebin을 비우고 작업하자
SHUTDOWN IMMEDIATE;
STARTUP;
select name, value from v$parameter where name = 'max_string_size';
NAME VALUE
---------------- ----------------
max_string_size EXTENDED
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001));
Table created.
desc extend_table;
Name Null? Type
----------------------------------------------------------------- -------- --------------------------------------------
DATA_VARCHAR VARCHAR2(4001)
DATA_NVARCHAR2 NVARCHAR2(2001)
DATA_RAW RAW(2001)
CREATE TABLE t1 (
id NUMBER,
varchar2_data VARCHAR2(32767),
nvarchar2_data NVARCHAR2(16383),
raw_data RAW(32767)
);
Table created.
INSERT INTO t1
SELECT 1,
RPAD('X', 32767, 'X') AS varchar2_data,
RPAD('X', 16383, 'X') AS nvarchar2_data,
UTL_RAW.cast_to_raw(RPAD('X', 32767, 'X')) as raw_data
FROM dual;
SELECT id,
LENGTH(varchar2_data),
LENGTH(nvarchar2_data),
LENGTH(raw_data)
FROM t1;
ID LENGTH(VARCHAR2_DATA) LENGTH(NVARCHAR2_DATA) LENGTH(RAW_DATA)
---------- --------------------- ---------------------- ----------------
1 32767 16383 32767
1 row selected.
-- 인덱스가 LOB 타입으로 자동으로 생성됨
SELECT index_name, index_type
FROM user_indexes
WHERE table_name = 'T1';
INDEX_NAME INDEX_TYPE
---------------------------------------- ---------------------------
SYS_IL0000093481C00004$$ LOB
SYS_IL0000093481C00003$$ LOB
SYS_IL0000093481C00002$$ LOB
-- 크기초과로 인덱스 생성 불가능
create index t1_idx01 on t1(varchar2_data asc);
create index t1_idx01 on t1(varchar2_data asc)
*
ERROR at line 1:
ORA-01450: maximum key length (6398) exceeded
create table identify_table (s_key number generated as identity primary key, data varchar2(30));
insert into identify_table (data) values ('test');
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 test
insert into identify_table (data) values ('test222');
update identify_table set data='11111' where s_key=1;
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
insert into identify_table values (3, '3333');
insert into identify_table values (3, '3333')
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column
-- 컬럼을 재정의하면 데이터를 직접 입력할 수 있다.
alter table identify_table modify ( s_key number generated by default as identity);
insert into identify_table values (5, '55555');
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
5 55555
-- 현재 시퀀스보다 큰 수를 수동으로 입력하고
-- 이후 자동으로 시퀀스로 채번하게 되면 UNIQUE 오류가 발생할 수 있다.
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
5 55555
21 3333
22 4444
23 test55555
insert into identify_table (data) values ('666666');
insert into identify_table (data) values ('77777');
insert into identify_table (data) values ('77777')
*
ERROR at line 1:
ORA-00001: unique constraint (JIGI.SYS_C0010318) violated
-- 시퀀스가 자동으로 생성됨
select sequence_name, cache_size, last_number from user_sequences;
SEQUENCE_NAME CACHE_SIZE LAST_NUMBER
------------------------------ ---------- -----------
ISEQ$$_93500 20 41
-- 테이블 생성 스크립트를 뽑으면 아래와 같음
CREATE TABLE JIGI.IDENTIFY_TABLE
(
S_KEY NUMBER DEFAULT "JIGI"."ISEQ$$_93500".nextval NOT NULL,
DATA VARCHAR2(30 BYTE)
);
create table parent(id number primary key);
create table child(cid number primary key, pid number);
alter table child add constraint fk_parent_child foreign key(pid) references parent(id) on delete cascade;
insert into parent values(1);
insert into parent values(2);
insert into child values(1,1);
insert into child values(2,1);
insert into child values(3,2);
commit;
select * from parent;
ID
----------
1
2
select * from child;
CID PID
---------- ----------
1 1
2 1
3 2
truncate table parent cascade;
select * from parent;
no rows selected
select * from child;
no rows selected
create table invisible (id number, invisible_col number invisible);
desc invisible;
Name Null? Type
-------------------------------- -------- --------------------------------------------
ID NUMBER
insert into invisible values (1, 1);
insert into invisible values (1, 1)
*
ERROR at line 1:
ORA-00913: too many values
insert into invisible (id, invisible_col) values (1, 1);
select * from invisible;
ID
----------
1
select id, invisible_col from invisible;
ID INVISIBLE_COL
---------- -------------
1 1
col owner format a30
col table_name format a30
col column_name for a20
select owner, table_name, column_name, hidden_column
from dba_tab_cols
where table_name = 'INVISIBLE';
OWNER TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ -------------------- ---
JIGI INVISIBLE INVISIBLE_COL YES
JIGI INVISIBLE ID NO
alter table invisible modify(invisible_col visible);
desc invisible;
Name Null? Type
--------------------------------------- -------- --------------------------------------------
ID NUMBER
INVISIBLE_COL NUMBER
create sequence test_seq start with 1;
create table seq_table (id number default test_seq.nextval, test varchar2(10));
insert into seq_table values(null, '1');
insert into seq_table values(default, '2');
insert into seq_table (test) values('3');
insert into seq_table values(100, '4');
commit;
select * from seq_table;
ID TEST
---------- ----------
1
1 2
2 3
100 4
insert into seq_table (test) values('5');
commit;
select * from seq_table;
ID TEST
---------- ----------
1
1 2
2 3
100 4
3 5
create table sales_information (
store_id number
, sales_date date default on null to_date('20991231', 'YYYYMMDD') not null
, sale_number number
, product_id number
, quantity number default on null 0 not null
, constraint pk_sales_information primary key (product_id, sales_date, sale_number)
);
insert into sales_information values (1, null, 1, 12345, null);
select * from sales_information;
STORE_ID SALES_DATE SALE_NUMBER PRODUCT_ID QUANTITY
---------- ------------------- ----------- ---------- ----------
1 2099-12-31 00:00:00 1 12345 0
select table_name, column_name, default_on_null from user_tab_columns where table_name ='SALES_INFORMATION';
TABLE_NAME COLUMN_NAME DEF
------------------------------ -------------------- ---
SALES_INFORMATION STORE_ID NO
SALES_INFORMATION SALES_DATE YES
SALES_INFORMATION SALE_NUMBER NO
SALES_INFORMATION PRODUCT_ID NO
SALES_INFORMATION QUANTITY YES
conn scott/tiger
create global temporary table gtt (id number, seq_number number);
grant all on gtt to jigi;
create sequence seq_session start with 1 session;
grant all on seq_session to jigi;
insert into gtt values ( 1, seq_session.nextval);
insert into gtt values ( 2, seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 1
2 2
commit;
select * from scott.gtt;
no rows selected
insert into gtt values ( 1, seq_session.nextval);
insert into gtt values ( 2, seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 3
2 4
commit;
conn jigi/oracle
select * from scott.gtt;
no rows selected
insert into scott.gtt values ( 1, scott.seq_session.nextval);
insert into scott.gtt values ( 2, scott.seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 1
2 2
commit;
select * from scott.gtt;
no rows selected
insert into scott.gtt values ( 1, scott.seq_session.nextval);
insert into scott.gtt values ( 2, scott.seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 3
2 4
create table emp_tab as select * from scott.emp;
create index emp_tab_ix01 on emp_tab(hiredate, deptno);
-- 동일컬럼에 비트맵 인덱스를 바로 생성하려고 하면 에러가 난다.
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno);
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno)
*
ERROR at line 1:
ORA-01408: such column list already indexed
-- 두번째 인덱스를 생성하기 위해 처음 인덱스를 invisible로 변경하면 인덱스가 생성된다.
alter index emp_tab_ix01 invisible;
Index altered.
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno);
Index created.
create table test_table (id number);
insert into test_table values (1);
insert into test_table values (2);
commit;
select * from test_table;
ID
----------
1
2
with
function plus_one(p_id number)
return number
is
begin
return p_id + 1;
end;
select plus_one(id) from test_table;
/
PLUS_ONE(ID)
------------
2
3
create or replace function helper (v_input number)
return number
accessible by (api) is -- 해당 FUNCTION은 API라는 PL/SQL에서만 호출가능
begin
return v_input + 1;
end;
JIGI@2016-11-22 11:32:45> select helper(1) from dual;
select helper(1) from dual
*
ERROR at line 1:
ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-904: insufficient privilege to access object HELPER
create or replace function api (v_input number)
return number
is
v_return number;
begin
v_return := helper(v_input);
return v_return;
end;
JIGI@2016-11-22 11:33:08> select api(1) from dual;
API(1)
----------
2
JIGI@2016-11-22 11:35:54>
CREATE OR REPLACE PROCEDURE ANSWER_ME (P_R BOOLEAN)
IS
BEGIN
IF P_R THEN
DBMS_OUTPUT.PUT_LINE('ANSWER IS TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('ANSWER IS FALSE');
END IF;
END;
SET SERVEROUTPUT ON
DECLARE
V_SQL VARCHAR2(1000);
V_BOOLEAN BOOLEAN := TRUE;
BEGIN
V_SQL := 'BEGIN ANSWER_ME(:X); END;';
EXECUTE IMMEDIATE V_SQL USING V_BOOLEAN;
END;
ANSWER IS TRUE
PL/SQL procedure successfully completed.
grant inherit privileges on user scott to public;
grant inherit privileges on user to tiger;
grant inherit any privileges to tiger;
위 3가지 방법으로 권한을 부여가능함
-- 테이블 생성
CREATE TABLE need_privs (id NUMBER);
INSERT INTO need_privs VALUES (1);
COMMIT;
-- function 생성
CREATE OR REPLACE FUNCTION get_new_value(v_input IN NUMBER)
RETURN NUMBER
-- AUTHID definer -- 해당 function을 만든 사용자 권한으로 실행한다는 의미
AUTHID current_user -- 해당 function을 호출자(실행자) 권한으로 실행한다는 의미
AS
v_number NUMBER := 0;
BEGIN
SELECT id + v_input INTO v_number FROM scott.need_privs;
RETURN v_number;
END;
SCOTT@2016-11-22 14:51:11> select get_new_value(1) from dual;
GET_NEW_VALUE(1)
----------------
2
-- 실행 권한 부여
SCOTT@2016-11-22 15:01:35> grant execute on get_new_value to hr;
Grant succeeded.
SCOTT@2016-11-22 15:01:45> conn hr/hr
Connected.
-- 권한이 없어서 오류발생
HR@2016-11-22 15:01:48> select scott.get_new_value(1) from dual;
select scott.get_new_value(1) from dual
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SCOTT.GET_NEW_VALUE", line 7
-- Role을 만들어본다.
HR@2016-11-22 15:02:04> conn scott/tiger
Connected.
SCOTT@2016-11-22 15:05:56> create role run_get_new_value;
create role run_get_new_value
*
ERROR at line 1:
ORA-01031: insufficient privileges
SCOTT@2016-11-22 15:06:11> conn /as sysdba
Connected.
SYS@2016-11-22 15:06:42> grant create role to scott;
Grant succeeded.
SYS@2016-11-22 15:07:14> conn scott/tiger
Connected.
SCOTT@2016-11-22 15:07:19> create role run_get_new_value;
Role created.
SCOTT@2016-11-22 15:07:32> grant select on need_privs to run_get_new_value;
Grant succeeded.
-- 12c에 새로생긴 기능
SCOTT@2016-11-22 15:07:57> grant run_get_new_value to function get_new_value;
Grant succeeded.
SCOTT@2016-11-22 15:08:25> conn hr/hr
Connected.
-- 결과가 잘 나옴
HR@2016-11-22 15:10:20> select scott.get_new_value(1) from dual;
SCOTT.GET_NEW_VALUE(1)
----------------------
2
HR@2016-11-22 15:10:27>
-- 디버깅을 위한 새로운 파라미터 제공
CREATE OR REPLACE procedure test_procedure
is
begin
dbms_output.put_line('$$plsql_unit_owner : ' || $$plsql_unit_owner);
dbms_output.put_line('$$plsql_unit_type : ' || $$plsql_unit_type);
end test_procedure;
/
HR@2016-11-22 15:39:00> exec test_procedure;
$$plsql_unit_owner : HR
$$plsql_unit_type : PROCEDURE