분석함수 : RANK, DENSE_RANK, LAG, LEAD
RANK() OVER (PARTITION BY 컬럼명 ORDER BY 컬럼명)
The sql extension is already loaded. To reload it, use:
%reload_ext sql
1 %sql oracle://ora_user:evan@127.0 .0 .1 :1521 /myoracle
분석 함수: 분석 함수 역시 특정 그룹별 집계를 담당하므로 집계 함수에 속한다.
PARTITION BY 절: 분석 함수로 계산될 대상 로우의 그룹(파티션)을 지정한다.
ORDER BY 절: 파티션 안에서의 순서를 지정한다.
WINDOW 절: 파티션으로 분할된 그룹에 대해서 더 상세한 그룹으로 분할할 때 사용된다. # Window 절
ROWS: 로우 단위로 window 절을 지정한다.
RANGE: 로우가 아닌 논리적인 범위로 window 절을 지정한다.
BETWEEN~AND: window 절의 시작과 끝 지점을 명시한다. BETWEEN을 명시하지 않고 두 번째 옵션만 지정하면이 지점이 시작 지점이 되고 끝 지점은 현재 로우가 된다.
UNBOUNDED PRECEDING: 파티션으로 구분된 첫 번째 로우가 시작 지점이 된다.
UNBOUNDED FOLLOWING: 파티션으로 구분된 마지막 로우가 끝 지점이 된다.
CURRENT ROW: 시작 및 끝 지점이 현재 로우가된다.
value_expr PRECEDING: 끝 지점일 경우, 시작 지점은 value_expr PRECEDING.
value_expr FOLLOWING: 시작 지점일 경우, 끝 지점은 value_expr FOLLOWING.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 % % sql SELECT department_id , emp_name , hire_date , salary , SUM (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS all_salary , SUM (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS first_current_sal , SUM (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS current_end_sal FROM employeesWHERE department_id IN (30 , 90 )
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
department_id
emp_name
hire_date
salary
all_salary
first_current_sal
current_end_sal
30
Den Raphaely
2002-12-07 00:00:00
11000
24900
11000
24900
30
Alexander Khoo
2003-05-18 00:00:00
3100
24900
14100
13900
30
Sigal Tobias
2005-07-24 00:00:00
2800
24900
16900
10800
30
Shelli Baida
2005-12-24 00:00:00
2900
24900
19800
8000
30
Guy Himuro
2006-11-15 00:00:00
2600
24900
22400
5100
30
Karen Colmenares
2007-08-10 00:00:00
2500
24900
24900
2500
90
Lex De Haan
2001-01-13 00:00:00
17000
58000
17000
58000
90
Steven King
2003-06-17 00:00:00
24000
58000
41000
41000
90
Neena Kochhar
2005-09-21 00:00:00
17000
58000
58000
17000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 % % sql SELECT department_id , emp_name , hire_date , salary , FIRST_VALUE (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS all_salary , FIRST_VALUE (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS first_current_sal , FIRST_VALUE (salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS current_end_sal FROM employeesWHERE department_id IN (30 , 90 )
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
department_id
emp_name
hire_date
salary
all_salary
first_current_sal
current_end_sal
30
Den Raphaely
2002-12-07 00:00:00
11000
11000
11000
11000
30
Alexander Khoo
2003-05-18 00:00:00
3100
11000
11000
3100
30
Sigal Tobias
2005-07-24 00:00:00
2800
11000
11000
2800
30
Shelli Baida
2005-12-24 00:00:00
2900
11000
11000
2900
30
Guy Himuro
2006-11-15 00:00:00
2600
11000
11000
2600
30
Karen Colmenares
2007-08-10 00:00:00
2500
11000
11000
2500
90
Lex De Haan
2001-01-13 00:00:00
17000
17000
17000
17000
90
Steven King
2003-06-17 00:00:00
24000
17000
17000
24000
90
Neena Kochhar
2005-09-21 00:00:00
17000
17000
17000
17000
p.211
계층형 쿼리
핵심 포인트 : CONNECT BY 조건문 정리- 계층형 쿼리의 구문은 다음과 같다.
SELECT expr1, expr2, … FROM 테이블 WHERE 조건 START WITH[최상위 조건] CONNECT BY [NOCYCLE][PRIOR 계층형 구조 조건]; –> 구조 : CONNECT BY PRIOR 하위 = 상위
START WITH 조건
계층형 구조에서 최상위 계층의 로우를 식별하는 조건을 명시한다.
START WITH가 시작한다는 의미이므로, 이 조건에 맞는 로우부터 시작해 계층형 구조를 풀어 나간다.
CONNECT BY 조건
계층형 구조가 어떤 식으로 연결되는지를 기술하는 부분이다.
부서 테이블은 parent_id에 상위 부서 정보를 갖고 있는데, 이를 표현하려면 ‘CONNECT BY PRIOR department_id = parent_id’로 기술해야 한다.
PRIOR는 계층형 쿼리에서만 사용할 수 있는 연산자로 ‘앞서의, 직전의’란 뜻이 있으므로, “이전 department_id = parent_id”라고 알아두면 이해하기 쉬울 것이다.
또한 ‘CONNECT BY parent_id = PRIOR department_id’처럼 PRIOR의 위치를 바꿀 수 있다.
1 2 3 4 5 6 7 8 9 % % sql SELECT department_id , LPAD(' ' , 3 * (LEVEL-1 )) || department_name , LEVEL FROM departmentsSTART WITH parent_id IS NULL CONNECT BY PRIOR department_id = parent_id
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
department_id
LPAD('',3*(LEVEL-1))||DEPARTMENT_NAME
LEVEL
10
총무기획부
1
20
마케팅
2
30
구매/생산부
2
170
생산팀
3
180
건설팀
3
200
운영팀
3
210
IT 지원
3
220
NOC
3
40
인사부
2
260
채용팀
3
50
배송부
2
80
영업부
2
190
계약팀
3
240
공공 판매사업팀
3
250
판매팀
3
90
기획부
2
60
IT
3
230
IT 헬프데스크
4
70
홍보부
3
100
자금부
3
130
세무팀
4
140
신용관리팀
4
150
주식관리팀
4
160
수익관리팀
4
110
경리부
3
120
재무팀
4
270
급여팀
4
manager_id는 해당 사원의 매니저 사번이 있다.
각 매니저는 사원 ID가 있다.
사원별 계층 구조를 만들고, 부서 테이블과 조인해서 부서명까지 조회한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 % % sql SELECT a.employee_id , LPAD(' ' , 3 * (LEVEL - 1 )) || a.emp_name , LEVEL , b.department_name FROM employees a , departments b WHERE a.department_id = b.department_idSTART WITH a.manager_id IS NULL CONNECT BY PRIOR a.employee_id = a.manager_id
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
employee_id
LPAD('',3*(LEVEL-1))||A.EMP_NAME
LEVEL
department_name
100
Steven King
1
기획부
101
Neena Kochhar
2
기획부
108
Nancy Greenberg
3
자금부
109
Daniel Faviet
4
자금부
110
John Chen
4
자금부
111
Ismael Sciarra
4
자금부
112
Jose Manuel Urman
4
자금부
113
Luis Popp
4
자금부
200
Jennifer Whalen
3
총무기획부
203
Susan Mavris
3
인사부
204
Hermann Baer
3
홍보부
205
Shelley Higgins
3
경리부
206
William Gietz
4
경리부
102
Lex De Haan
2
기획부
103
Alexander Hunold
3
IT
104
Bruce Ernst
4
IT
105
David Austin
4
IT
106
Valli Pataballa
4
IT
107
Diana Lorentz
4
IT
114
Den Raphaely
2
구매/생산부
115
Alexander Khoo
3
구매/생산부
116
Shelli Baida
3
구매/생산부
117
Sigal Tobias
3
구매/생산부
118
Guy Himuro
3
구매/생산부
119
Karen Colmenares
3
구매/생산부
120
Matthew Weiss
2
배송부
125
Julia Nayer
3
배송부
126
Irene Mikkilineni
3
배송부
127
James Landry
3
배송부
128
Steven Markle
3
배송부
180
Winston Taylor
3
배송부
181
Jean Fleaur
3
배송부
182
Martha Sullivan
3
배송부
183
Girard Geoni
3
배송부
121
Adam Fripp
2
배송부
129
Laura Bissot
3
배송부
130
Mozhe Atkinson
3
배송부
131
James Marlow
3
배송부
132
TJ Olson
3
배송부
184
Nandita Sarchand
3
배송부
185
Alexis Bull
3
배송부
186
Julia Dellinger
3
배송부
187
Anthony Cabrio
3
배송부
122
Payam Kaufling
2
배송부
133
Jason Mallin
3
배송부
134
Michael Rogers
3
배송부
135
Ki Gee
3
배송부
136
Hazel Philtanker
3
배송부
188
Kelly Chung
3
배송부
189
Jennifer Dilly
3
배송부
190
Timothy Gates
3
배송부
191
Randall Perkins
3
배송부
123
Shanta Vollman
2
배송부
137
Renske Ladwig
3
배송부
138
Stephen Stiles
3
배송부
139
John Seo
3
배송부
140
Joshua Patel
3
배송부
192
Sarah Bell
3
배송부
193
Britney Everett
3
배송부
194
Samuel McCain
3
배송부
195
Vance Jones
3
배송부
124
Kevin Mourgos
2
배송부
141
Trenna Rajs
3
배송부
142
Curtis Davies
3
배송부
143
Randall Matos
3
배송부
144
Peter Vargas
3
배송부
196
Alana Walsh
3
배송부
197
Kevin Feeney
3
배송부
198
Donald OConnell
3
배송부
199
Douglas Grant
3
배송부
145
John Russell
2
영업부
150
Peter Tucker
3
영업부
151
David Bernstein
3
영업부
152
Peter Hall
3
영업부
153
Christopher Olsen
3
영업부
154
Nanette Cambrault
3
영업부
155
Oliver Tuvault
3
영업부
146
Karen Partners
2
영업부
156
Janette King
3
영업부
157
Patrick Sully
3
영업부
158
Allan McEwen
3
영업부
159
Lindsey Smith
3
영업부
160
Louise Doran
3
영업부
161
Sarath Sewall
3
영업부
147
Alberto Errazuriz
2
영업부
162
Clara Vishney
3
영업부
163
Danielle Greene
3
영업부
164
Mattea Marvins
3
영업부
165
David Lee
3
영업부
166
Sundar Ande
3
영업부
167
Amit Banda
3
영업부
148
Gerald Cambrault
2
영업부
168
Lisa Ozer
3
영업부
169
Harrison Bloom
3
영업부
170
Tayler Fox
3
영업부
171
William Smith
3
영업부
172
Elizabeth Bates
3
영업부
173
Sundita Kumar
3
영업부
149
Eleni Zlotkey
2
영업부
174
Ellen Abel
3
영업부
175
Alyssa Hutton
3
영업부
176
Jonathon Taylor
3
영업부
177
Jack Livingston
3
영업부
179
Charles Johnson
3
영업부
201
Michael Hartstein
2
마케팅
202
Pat Fay
3
마케팅
CONNECT BY ~ AND : AND를 통해 추가로 조건을 붙인다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 % % sql SELECT a.employee_id , LPAD(' ' , 3 * (LEVEL - 1 )) || a.emp_name , LEVEL , b.department_name FROM employees a , departments b WHERE a.department_id = b.department_idSTART WITH a.manager_id IS NULL CONNECT BY PRIOR a.employee_id = a.manager_id AND a.department_id = 30
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
employee_id
LPAD('',3*(LEVEL-1))||A.EMP_NAME
LEVEL
department_name
100
Steven King
1
기획부
114
Den Raphaely
2
구매/생산부
115
Alexander Khoo
3
구매/생산부
116
Shelli Baida
3
구매/생산부
117
Sigal Tobias
3
구매/생산부
118
Guy Himuro
3
구매/생산부
119
Karen Colmenares
3
구매/생산부
CONNECT BY PRIOR 자식컬럼 = 부모컬럼 : 부모에서 자식으로 트리 구성 (TOP DOWN) -> 일반적인 구조
CONNECT BY PRIOR 부모컬럼 = 자식컬럼 : 자식에서 부모로 트리 구성 (Bottom UP)
CONNECT BY NOCYCLE PRIOR = 무한루프 방지- p.226 WITH 절
kor_loan_status 테이블에서 연도별 최종월 기준 가장 대출이 많은 도시와 잔액을 구한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 % % sql SELECT b2.* FROM ( SELECT period , region, sum (loan_jan_amt) jan_amt FROM kor_loan_status GROUP BY period , region ) b2, ( SELECT b.period, MAX (b.jan_amt) max_jan_amt FROM ( SELECT period , region, sum (loan_jan_amt) jan_amt FROM kor_loan_status GROUP BY period , region ) b, ( SELECT MAX (PERIOD ) max_month FROM kor_loan_status GROUP BY SUBSTR(PERIOD , 1 , 4 ) ) a WHERE b.period = a.max_month GROUP BY b.period ) c WHERE b2.period = c.period AND b2.jan_amt = c.max_jan_amt ORDER BY 1
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
period
region
jan_amt
201112
서울
334728.3
201212
서울
331572.3
201311
서울
334062.7
1 - WITH 절은 별칭으로 사용한 SELECT 문의 FROM 절에 다른 SELECT 구문의 별칭 참조가 가능하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 % % sql WITH b2 AS (SELECT period , region, sum (loan_jan_amt) jan_amt FROM kor_loan_status GROUP BY period , region) , c AS (SELECT b.period, MAX (b.jan_amt) max_jan_amt FROM (SELECT period , region, sum (loan_jan_amt) jan_amt FROM kor_loan_status GROUP BY period , region) b , (SELECT MAX (PERIOD ) max_month FROM kor_loan_status GROUP BY SUBSTR(PERIOD , 1 , 4 ) ) a WHERE b.period = a.max_month GROUP BY b.period ) SELECT b2.* FROM b2, cWHERE b2.period = c.period AND b2.jan_amt = c.max_jan_amt ORDER BY 1
* oracle://ora_user:***@127.0.0.1:1521/myoracle
0 rows affected.
period
region
jan_amt
201112
서울
334728.3
201212
서울
331572.3
201311
서울
334062.7
Reference : 오라클 SQL과 PL/SQK을 다루는 기술