-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsql-study-day9-jimin
353 lines (330 loc) · 16.2 KB
/
sql-study-day9-jimin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
## 07-1 하나의 열에 출력 결과를 담는 다중행 함수
- **다중행 함수**(multiple-row function)? **여러 행**을 바탕으로 **하나의 결과 값(하나의 행)**을 도출해내기 위해 사용하는 함수
- 다중행 함수 = 그룹 함수 = 복수행 함수
- sum 함수를 통해 급여 합계 출력하기
```sql
SELECT SUM(SAL)
FROM EMP;
```
- sum 함수는 **SELECT문으로 조회된 행**에 **지정한 열 값을 모두 더한 값**을 반환해주는 함수이다.
- 다중행 함수를 사용한 SELECT절에는 기본적으로 여러 행이 결과로 나올 수 있는 열을 함꼐 사용할 수 없다.
==> 다음과 같은 SELECT문은 실행되지 못하고 오류가 발생한다.
```sql
SELECT ENAME, SUM(SAL)
FROM EMP;
```
- 결과 값이 **한 행**으로 나온 데이터 SUM(SAL)과 **여러 행**이 나올 수 있는 데이터(ENAME)을 **함께 명시**했기 때문에 **오류**가 발생한다.
- 다중행 함수들
|함수|설명|
|:----------:|-------------------|
|SUM|지정한 데이터의 합 반환|
|COUNT|지정한 데이터의 개수 반환|
|MAX|지정한 데이터 중 최댓값 반환|
|MIN|지정한 데이터 중 최솟값 반환|
|AVG|지정한 데이터의 평균값 반환|
### - 합계를 구하는 SUM 함수
- SUM함수는 데이터의 합을 구하는 함수이다.
- 기본 형식
```sql
SUM([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[합계를 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
```
- SUM함수를 분석하는 용도로 사용한다면 다음과 같이 함수를 작성한 후 OVER절을 사용할 수도 있다.
```sql
SUM([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[합계를 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
OVER(분석을 위한 여러 문법을 지정)(선택)
```
- 추가 수당 합계 구하기
- 추가 수당 열은 NULL이 존재하는 열이다.
- 따라서 덧셈(+)연산만으로 합계를 구했다면 결과는 NULL이 나왔을 것이다.
- 하지만 , **SUM 함수는 NULL 데이터는 자동으로 제외**하고 합계를 구하므로 별다른 문제 없이 결과를 출력받을 수 있다.
```sql
SELECT SUM(COMM)
FROM EMP;
```
#### -- SUM함수와 DISTINCT, ALL 함께 사용하기
- SUM 함수를 작성할 떄 생략 가능 옵션 DISTINCT, ALL을 사용한 결과 비교하기
- 급여 합계 구하기(DISTINCT, ALL 사용)
```sql
SELECT SUM(DISTINCT SAL),
SUM(ALL SAL),
SUM(SAL)
FROM EMP;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/55513452-ba77-43da-a8b5-90920c304497/image.png)
- ALL을 사용한 SUM함수의 결과 == 아무 옵션을 지정하지 않은 SUM함수의 결과
- DISTINCT를 지정하면 중복 데이터가 제거 되고 합계가 계산되기에, 다른 값이 나오게 된다.
- 하지만, 일반적으로 합계를 구할 때 같은 값을 제외하는 경우는 많지 않다.
### - 데이터의 개수를 구해 주는 COUNT 함수
- COUNT 함수는 **데이터의 개수**를 출력하는데 사용한다.
- COUNT 함수에 *을 사용하면 **SELECT문의 결과 값으로 나온 행 데이터의 개수**를 반환해준다.
- 기본 형식
```sql
COUNT([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[개수를 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
OVER(분석을 위한 여러 문법 지정)(선택)
```
- SUM함수에서와 마찬가지로 DISTINCT나 ALL을 사용하여 특정 데이터 또는 열을 지정할 수 있다.
- 옵션을 지정하지 않았을 경우, 중복을 허용하여 결과 값을 반환하는 ALL을 기본으로 한다.
- EMP 테이블의 데이터 개수 출력하기(사원수, 행 수)
```sql
SELECT COUNT(*)
FROM EMP;
```
- WHERE절의 조건식을 함께 사용하면 유용하게 사용할 수 있다.
- 부서 번호가 30번인 직원 수 구하기
```sql
SELECT COUNT(*)
FROM EMP
WHERE DEPTNO = 30;
```
- 특정 조건을 만족하는 데이터를 COUNT함수와 함꼐 사용한 결과 값은 다양한 분야에서 활용할 수 있다.
- 웹 커뮤니티
- 특정회원이 작성한 총 글수, 댓글 수, 글에서 받은 찬성 수, 반대 수 등을 조합
--> 어떤 상품이 많이 구매 되었는지 분석 가능
--> 화면의 어느 위치에 있는 항목이 자주 선택되었는지 분석 가능
#### -- COUNT함수와 DISTINCT, ALL 함께 사용하기
```sql
SELECT COUNT(DISTINCT SAL),
COUNT(ALL SAL),
COUNT(SAL)
FROM EMP;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/cfc5b8ad-8fa3-456d-8739-9bc70e5d56db/image.png)
- COUNT 함수를 사용하면 NULL이 데이터로 포함되어 있을 경우, NULL 데이터는 반환 개수에서 제외된다.
- COUNT 함수를 사용하여 추가 수당 열 개수 출력하기
```sql
SELECT COUNT(COMM)
FROM EMP;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/c9c54da2-4b22-4faf-a9cb-fc049b7a1666/image.png)
- COUNT 함수와 IS NOT NULL을 사용하여 추가 수당 열 개수 출력하기
```sql
SELECT COUNT(COMM)
FROM EMP
WHERE COMM IS NOT NULL;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/ba8e5818-d6b7-4e3a-8c92-07de53d7d1cf/image.png)
- COUNT 함수와 IS NULL을 사용하는 경우
```sql
SELECT COUNT(COMM)
FROM EMP
WHERE COMM IS NULL;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/fb0ce1b6-e660-46d2-b4f9-58fd152c9a76/image.png)
### - 최댓값과 최솟값을 구하는 MAX, MIN 함수
- MAX함수와 MIN함수는 단어 의미 그대로 입력 데이터 중 최댓값과 최솟값을 반환하는 함수이다.
- MAX의 기본형식
```sql
MAX([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[최댓값을 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
OVER(분석을 위한 여러 문법 지정)(선택)
```
- MIN의 기본형식
```sql
MIN([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[최솟값을 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
OVER(분석을 위한 여러 문법 지정)(선택)
```
#### -- 숫자 데이터에 MAX, MIN 함수 사용하기
- MAX와 MIN 함수도 DISTINCT나 ALL을 지정할 수 있지만 최댓값과 최솟값은 중복 제거와 무관하기 때문에 실제로는 지정하지 않는다.
- 부서 번호가 10번인 사원들의 최대 급여 출력하기
```sql
SELECT MAX(SAL)
FROM EMP
WHERE DEPTNO = 10;
```
- 부서 번호가 10번인 사원들의 최소 급여 출력하기
```sql
SELECT MIN(SAL)
FROM EMP
WHERE DEPTNO = 10;
```
#### -- 날짜 데이터에 MAX, MIN 함수 사용하기
- 오라클 데이터베이스에서는 날짜 및 문자 데이터 크기 비교가 가능하다.
- 최근 == 연도가 큼
- 오래됨 == 연도가 작음
- 부서 번호가 20인 사원의 입사일 중 제일 최근 입사일 출력하기
```sql
SELECT MAX(HIREDATE)
FROM EMP
WHERE DEPTNO=20;
```
- 부서 번호가 20인 사원의 입사일 중 제일 오래된 입사일 출력하기
```sql
SELECT MIN(HIREDATE)
FROM EMP
WHERE DEPTNO=20;
```
## - 평균값을 구하는 AVG 함수
- AVG함수는 입력 데이터의 평균 값을 구하는 함수이다.
- 숫자 또는 숫자로 암시적 형 변환이 가능한 데이터만 사용할 수 있다.
- 기본 형식
```sql
AVG([DISTINCT, ALL 중 하나를 선택하거나
아무 값도 지정하지 않음(선택)]
[평균값을 구할 열이나 연산자, 함수를 사용한 데이터(필수)])
OVER(분석을 위한 여러 문법 지정)(선택)
```
- 부서 번호가 30인 사원들의 평균 급여 출력하기
```sql
SELECT AVG(SAL)
FROM EMP
WHERE DEPTNO=30;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/06954578-4d99-4156-8197-3a7629cb51c5/image.png)
- 자주 사용하는 방식은 아니지만, DISTINCT를 지정하면 중복 값을 제외하고 평균값을 구하므로 결과 값이 달라질 수 있다.
- DISTINCT를 지정하지 않으면 중복을 허용하는 ALL이 기본값이다.
- DISTINCT로 중복을 제거한 부서 30인 사원들의 급여 열의 평균 급여 구하기
```sql
SELECT AVG(DISTINCT SAL)
FROM EMP
WHERE DEPTNO=30;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/5de86ddd-b4d9-4cf5-b854-a1a68d1f5e10/image.png)
## 07-2 결과 값을 원하는 열로 묶어 출력하는 GROUP BY절
- 다중행 함수는 지정 테이블의 데이터를 가공하여 하나의 결과 값만 출력한다.
- DEPTNO 열 값별로 급여의 평균 값을 구하려면 각 부서 평균 값을 구하기 위해 SELECT문을 다음과 같이 하나하나 제작해야 한다.
```sql
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 10;
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 20;
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 30;
```
- 위의 결과 값을 하나로 통합해서 보려면 집합 연산자를 다음과 같이 활용 할 수 있다.
```sql
SELECT AVG(SAL), '10' AS DEPTNO FROM EMP WHERE DEPTNO = 10
UNION ALL
SELECT AVG(SAL), '20' AS DEPTNO FROM EMP WHERE DEPTNO = 20
UNION ALL
SELECT AVG(SAL), '30' AS DEPTNO FROM EMP WHERE DEPTNO = 30;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/7e0abb32-c552-4350-9481-a07dfb7b1331/image.png)
- AVG 함수 옆에 부서 코드를 열을 바로 붙일 수 없기 때문에 10, 20, 30을 직접 작성하여 별칭을 준다.
--> 필요에 따라 이런 식으로 데이터를 강제로 넣어 결과 열에 명시하기도 한다.
- 하지만 위와 같은 방식은 번거롭기도 하고, 이후 특정 부서를 추가하거나 삭제할 때마다 SQL문을 수정해야 하므로 바람직하지 않다.
### - GROUP BY절의 기본 사용법
- **그룹화**? 여러 데이터에서 **의미 있는 하나의 결과**를 **특정 열 값별로** 묶어서 출력할 데이터
- SELECT문에서는 GROUP BY절을 작성하여 데이터를 그룹화 할 수 있다.
- 다음과 같이 순서에 맞게 장성하며 그룹으로 묶을 기준 열을 지정한다.
- **순서:
SELECT > FROM > WHERE > GROUP BY > ORDER BY**
- 기본형식
```sql
SELECT [조회할 열1 이름], [열2 이름], ..., [열N 이름]
FROM [조회할 테이블 이름]
WHERE [조회할 행을 선별하는 조건식]
GROUP BY [그룹화할 열을 지정(여러개 지정 가능)]
ORDER BY [정렬하려는 열 지정]
```
- GROUP BY절에 명시하는 열은 여러 개 지정할 수 있다.
- 먼저 지정한 열로 대그룹을 나누고 그 다움 지정한 열로 소그룹을 나눈다.
- GROUP BY절에는 별칭이 인식되지 않는다.
- GROUP BY절을 사용하여 부서별 평균 급여 출력하기
```sql
SELECT AVG(SAL), DEPTNO
FROM EMP
GROUP BY DEPTNO;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/f47d7684-00f2-4877-a918-6bd417b996da/image.png)
- /**각 부서**/의 /**직책별**/ /**평균 급여**/를 알고 싶다면, GROUP BY절에 JOB 열을 추가로 명시하여 오른쪽과 같이 작성할 수 있다.
![](https://velog.velcdn.com/images/mini_mouse_/post/d847bbfe-96bf-47bd-bd04-e0d512fde82b/image.png)
```sql
SELECT AVG(SAL), DEPTNO, JOB
FROM EMP
GROUP BY DEPTNO, JOB
ORDER BY DEPTNO, JOB;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/a43deaab-82df-429c-b495-95e432a774a5/image.png)
- GROUP BY절을 사용한 그룹화 이후, 가지런한 정렬 결과를 원한다면 ORDER BY절로 정렬 기준을 정해 주어야 한다.
- 위의 예시에서는 GROUP BY절에 명시된 부서 번호로 그룹을 먼저 묶고, 그룹 내에서 사원 직책 여를 기준으로 다시 소그룹을 묶어 급여 평균을 출력한다.
### - GROUP BY절을 사용할 때 유의할 점
- **다중행 함수를 사용하지 않은** 일반 열을 **GROUP BY절에 명시하지 않으면**, **SELECT절에서 사용할 수 없다**.
- GROUP BY절에 없는 열을 SELECT절에 포함했을 경우
--> 오류가 나게 된다.
```sql
SELECT ENAME, DEPTNO, AVG(SAL)
FROM EMP
GROUP BY DEPTNO;
```
- DEPTNO를 기준으로 그룹화 되어, DEPTNO열과 AVG(SAL) 열은 한 행으로 출력되지만, ENAME열은 여러 행으로 구성되어 각 열별 데이터 수가 달라져서 출력이 불가능하다.
- **GROUP BY절**을 사용할 때는 **SELECT절의 열**도 유심히 살펴 봐야 한다.
- <span style="background-color: rgba(242,179,188,0.5)">**GROUP BY절을 사용한 그룹화는, 그룹화 된 열 외에 일반 열을 SELECT절에 명시할 수 없다.**</span>
==> 이점만 유의하면 큰 문제가 발생하지 않을 것!
## 07-3 GROUP BY절에 조건을 줄 때 사용하는 HAVING절
- **HAVING절**은 **SELECT문에 GROUP BY절이 존재할 때만** 사용할 수 있다.
- **GROUP BY절을 통해 그룹화된 결과 값의 범위를 제한**하는데 사용된다.
- 각 부서의 직책별 평균 급여를 구하되, 그 평균 급여가 2000이상인 그룹만 출력하려면 다음과 같이 SELECT문에 GROUP BY절과 HAVING절을 작성하면 된다.
```sql
SELECT DEPTNO, JOB, AVG(SAL)
FROM EMP
GROUP BY DEPTNO, JOB
HAVING AVG(SAL) >= 2000
ORDER BY DEPTNO, JOB;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/eb35bf09-8046-4644-9aa8-6140b3473b6f/image.png)
- HAVING절을 통해 AVG(SAL) 값이 2000을 넘지 않는 그룹의 결과는 출력되지 않음을 알 수 있다.
### - HAVING절의 기본 사용법
- HAVING절의 기본형식
```sql
SELECT [조회할 열1 이름], [열2 이름], ..., [열N 이름]
FROM [조회할 테이블 이름]
WHERE [조회할 행을 선별하는 조건식]
GROUP BY [그룹화할 열을 지정(여러개 지정 가능)]
HAVING [출력 그룹을 제한하는 조건식]
ORDER BY [정렬하려는 열 지정]
```
- HAVING절은 GROUP BY절이 존재하는 경우, GROUP BY절 바로 다음에 작성한다.
- GROUP BY와 마찬가지로 별칭은 사용할 수 없다.
### - HAVING절을 사용할 때 유의점
- HAVING절도 WHERE절처럼 지정한 조건식이 참인 결과만 출력한다는 점에서 비슷한 부분이 있다.
- 차이점: 쓰임새가 다르다.
**WHERE -> 출력 대상 행을 제한
HAVING -> 그룹화된 대상을 출력에서 제한**
- 만약, 출력 결과를 제한하기 위해 HAVING을 사용하지 않고 조건식을 WHERE절에 명시하면 다음과 같이 SELECT문이 실행되지 않고 오류가 발생한다.
-> 출력 행을 제한하는 WHERE절에서는 그룹화된 데이터 AVG(SAL)을 제한하는 조건식을 지정할 수 없다.
==> **다중행 결과 값은 WHERE에서 제한 할 수 없다.**
```sql
SELECT DEPTNO, JOB, AVG(SAL)
FROM EMP
WHERE AVG(SAL) >= 2000
GROUP BY DEPTNO, JOB
ORDER BY DEPTNO, JOB;
```
### - WHERE절과 HAVING절의 차이점
- WHERE절을 사용하지 않고 HAVING절만 사용한 경우
```sql
SELECT DEPTNO, JOB, AVG(SAL)
FROM EMP
GROUP BY DEPTNO, JOB
HAVING AVG(SAL) >= 2000
ORDER BY DEPTNO, JOB;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/79fd4f7e-5bfa-4cfb-9fe8-8a6ca880e8f4/image.png)
- WHERE절과 HAVING절을 모두 사용한 경우
```sql
SELECT DEPTNO, JOB, AVG(SAL)
FROM EMP
WHERE SAL <= 3000
GROUP BY DEPTNO, JOB
HAVING AVG(SAL) >= 2000
ORDER BY DEPTNO, JOB;
```
![](https://velog.velcdn.com/images/mini_mouse_/post/d5aea9e4-e6ac-46bf-9da8-e38f057c9440/image.png)
- WHERE절을 추가한 SELECT문에서는 10번 부서의 PRESIDENT 데이터가 출력되지 않는다.
-> **WHERE절**이,
**GROUP BY절과 HAVING절을 사용한 데이터 그룹화**보다,
**먼저 출력 대상이 될 행을 제한**하기 때문이다.
- 즉, GROUP BY절을 사용해 부서별, 직책별 데이터를 그룹화하기 전에, 급여가 3000를 초과한 급여를 받는 사원의 데이터는 결과에서 먼저 제외되어 그룹화 대상에 속하지도 못하게 되는 것이다.
- 따라서, **WHERE절을 실행한 후에 나온 결과 데이터**가
**GROUP BY절과 HAVING절의 그룹화 대상 데이터**가 된다.
=> WHERE -> GROUP BY + HAVING
- 그룹이 만들어지기 전에 걸러진 데이터는 그룹화가 진행되지 않는다.
- 예; 연예인 엔터테인먼트에서 새로운 여성 아이돌 그룹을 결성하려고 할 때, 남성 연예인 지망생은 처음부터 고려 대상에서 제외된다.
> **GROUP BY로 그룹을 나누는 대상 데이터를 처음부터 제외할 목적이라면 WHERE절을 함께 사용한다.**
- GROUP BY절을 수행하기 전에 WHERE절의 조건식으로 출력행의 제한이 먼저 이루어 진다.