[SQL Fundamentals] 04. Group By์ ์ง๊ณ ํจ์(Aggregate Function)
by Hi.Claire๐ฅ๏ธ ๋ฐ์ดํฐ ๋ถ์ SQL Fundamentals (๊ถ์ฒ ๋ฏผ, ์ธํ๋ฐ)
์น์ 4. Group By์ ์ง๊ณ ํจ์ (Aggregate Function)
4-1. Group By์ ์ดํด
Group By
Group By ์ ์ ๊ธฐ์ ๋ ์ปฌ๋ผ ๊ฐ(๋๋ ๊ฐ๊ณต ์ปฌ๋ผ๊ฐ)์ผ๋ก ๊ทธ๋ฃนํํ ๋ค ์ง๊ณ ํจ์ (Aggregation Function)์ ํจ๊ป ์ฌ์ฉ๋์ด ๊ทธ๋ฃนํ๋ ์ง๊ณ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ค.
๊ฒฐ๊ณผ ์งํฉ์ Group By ์ ์ ๊ธฐ์ ๋ ์ปฌ๋ผ๊ฐ์ผ๋ก ๋ฐ๋์ 1์ ์งํฉ์ ๊ฐ์ง๊ฒ ๋๋ค.
select ์ ์๋ Group By ์ ์ ๊ธฐ์ ๋ ์ปฌ๋ผ(๋๋ ๊ฐ๊ณต ์ปฌ๋ผ)๊ณผ ์ง๊ณ ํจ์๋ง ์ฌ์ฉ๋ ์ ์๋ค.
(์ฌ์ฉ๋ฒ)
SELECT <column(s)>
FROM <table>
WHERE <condition> -- group by ํ ๋์์ filtering ์กฐ๊ฑด
GROUP BY <column(s)> -- group by ์ ์ฉํ ์ปฌ๋ผ๋ช
HAVING <condition> -- group by ๊ฒฐ๊ณผ์ filtering ์กฐ๊ฑด
ORDER BY <columns(s)>;
(์์) emp ํ ์ด๋ธ์ group by ์์
1
2
3
4
5
6
|
select deptno, sum(sal) as sum_sal
from hr.emp
where job != 'SALARYMAN'
group by deptno
having avg(sal) > 2000
order by deptno;
|
์์ ์์๋ก ๋ฐ์ดํฐ๊ฐ filtering ๋๋ ์์๋ฅผ ์ดํด๋ณด์.
๋จผ์ WHERE ์ ์ ์ํด job์ด 'SALARYMAN'์ด ์๋ ๋ฐ์ดํฐ๊ฐ 1์ฐจ์ ์ผ๋ก filtering ๋๋ค.
๊ทธ ๋ค์ Group By ์ ์ ์ํด deptno๋ก ๊ทธ๋ฃนํ๋ฅผ ์ํํ๋ค.
๋ง์ง๋ง์ผ๋ก having ์ ์ ์ํด sal์ ํ๊ท ๊ฐ์ด 2000 ์ด์์ธ ๊ทธ๋ฃน๋ค๋ก ํ ๋ฒ ๋ filtering๋๋ค.
Group By ์ ์ฉ ๋ก์ง
์์ ๊ฐ์ ๊ณผ์ ์ ํตํด Group By๊ฐ ๋์ํ๋ค.
(์์) emp ํ ์ด๋ธ์ group by ์์
1
2
3
4
|
select deptno, count(*) as emp_count, sum(sal) as sum_sal, round(avg(sal),3) as avg_sal, max(sal) as max_sal
from hr.emp
group by deptno
order by deptno;
|
emp ํ ์ด๋ธ์ PK๋ empno๋ค.
์ฆ, emp ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ empno์ ๋ํด uniqueํ๋ฉฐ, empno๋ก 1์ ์งํฉ์ ๊ฐ์ง๋ค.
ํ์ง๋ง group by๊ฐ ์ํ๋๋ฉด์ ํด๋น ์งํฉ์ด ๋ญ๊ทธ๋ฌ์ง๊ฒ ๋๋ฉฐ, group by ๊ฒฐ๊ณผ ์งํฉ์ deptno๋ฅผ PK๋ก ๊ฐ์ง๊ฒ ๋๋ค.
์ฆ, group by ๊ฒฐ๊ณผ ์งํฉ์ deptno๋ก uniqueํ๋ฉฐ, deptno๋ก 1์ ์งํฉ์ ๊ฐ์ง๋ค.
4-2. Group By ์ค์ต
์ค์ต ์์
1. emp ํ ์ด๋ธ์์ ๋ถ์๋ณ ์ต๋ ๊ธ์ฌ, ์ต์ ๊ธ์ฌ, ํ๊ท ๊ธ์ฌ๋ฅผ ๊ตฌํ๋ ํ๊ท ๊ธ์ฌ๊ฐ 2000 ์ด์์ธ ๊ฒฝ์ฐ๋ง ์ถ์ถ
1
2
3
4
5
|
select deptno, max(sal) as max_sal, min(sal) as min_sal, round(avg(sal),2) as avg_sal
from emp
group by deptno
having avg(sal) >= 2000
order by deptno;
|
round(val [, n])
postgreSQL ๋ฐ์ฌ๋ฆผ ํจ์
์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ง ์ฃผ์ด์ง ๊ฒฝ์ฐ : ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ฃผ์ด์ง ๊ฐ์ ๋ฐ์ฌ๋ฆผํ ๋ค ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์๊ฐ์ ๋ฆฌํดํ๋ค.
์ฒซ ๋ฒ์งธ, ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๊ฐ ๋ชจ๋ ์ฃผ์ด์ง ๊ฒฝ์ฐ : ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ฃผ์ด์ง ๊ฐ์ ๋ฐ์ฌ๋ฆผํ ๋ค ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ฃผ์ด์ง ๊ฐ๋งํผ ์์์ ์๋ ์๋ฆฌ์๋ฅผ ํ์ํ๋ค.
(์์1) round(avg(sal))
avg(sal)์ ๋ฐ์ฌ๋ฆผํ์ฌ ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์๊ฐ์ ๋ฆฌํดํ๋ค.
(์์2) round(avg(sal), 2)
avg(sal)์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ฌ๋ฆผํ์ฌ ์์์ ์๋ 2์๋ฆฌ๊น์ง ํ์ํ๋ค.
2. emp ํ ์ด๋ธ์์ ๋ถ์๋ณ ์ต๋ ๊ธ์ฌ, ์ต์ ๊ธ์ฌ, ํ๊ท ๊ธ์ฌ๋ฅผ ๊ตฌํ๋ ํ๊ท ๊ธ์ฌ๊ฐ 2000 ์ด์์ธ ๊ฒฝ์ฐ๋ง ์ถ์ถ (with ์ ์ ์ด์ฉ)
1
2
3
4
5
6
7
8
9
|
with
temp as (
select deptno, max(sal) as max_sal, min(sal) as min_sal, round(avg(sal),2) as avg_sal
from emp
group by deptno
)
select deptno, max_sal, min_sal, avg_sal
from temp
where avg_sal >= 2000;
|
3. ๋ถ์๋ช SALES์ RESEARCH ์์ ์ง์๋ณ๋ก ๊ณผ๊ฑฐ๋ถํฐ ํ์ฌ๊น์ง ๋ชจ๋ ๊ธ์ฌ๋ฅผ ์ทจํฉํ ํ๊ท ๊ธ์ฌ ๊ตฌํ๊ธฐ
1
2
3
4
5
6
7
|
select b.empno, max(b.ename) as ename, round(avg(c.sal),2) as avg_sal
from hr.dept a
join hr.emp b on a.deptno = b.deptno
join hr.emp_salary_hist c on b.empno = c.empno
where a.dname in('SALES', 'RESEARCH')
group by b.empno
order by 1;
|
(ํ์ด ์์)
1) ๋ถ์๋ช SALES, RESEARCH ๋ฐ์ดํฐ๋ง filtering ํ๋ค.
from hr.dept a
where a.dname in('SALES', 'RESEARCH')
2) join์ ํตํด ํด๋น ๋ถ์ ์์ ์ง์ ์ ๋ณด์ ์ง์์ ๊ธ์ฌ์ด๋ ฅ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค.
from hr.dept a
join hr.emp b on a.deptno = b.deptno
join hr.emp_salary_hist c on b.empno = c.empno
3) group by๋ฅผ ํตํด ๋ฐ์ดํฐ ์งํฉ์ empno๋ก 1์ ์งํฉ์ด ๋๋๋ก ํ๋ค.
group by b.empno
4) ์ง๊ณ ํจ์๋ฅผ ํตํด ์ํ๋ ์ง๊ณ์ฑ ์ ๋ณด๋ฅผ ๊ตฌํ๋ค.
select b.empno, max(b.ename) as ename, round(avg(c.sal),2) as avg_sal
group by b.empno
4. ๋ถ์๋ช SALES์ RESEARCH ์์ ์ง์๋ณ๋ก ๊ณผ๊ฑฐ๋ถํฐ ํ์ฌ๊น์ง ๋ชจ๋ ๊ธ์ฌ๋ฅผ ์ทจํฉํ ํ๊ท ๊ธ์ฌ ๊ตฌํ๊ธฐ (with ์ ๋ก ํ๊ธฐ)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
with
temp as (
select e.empno, e.ename, esh.fromdate, esh.todate, esh.sal
from dept d
join emp e on d.deptno = e.deptno
join emp_salary_hist esh on e.empno = esh.empno
where d.dname in ('SALES', 'RESEARCH')
)
select empno, max(ename), round(avg(sal),2) as avg_sal
from temp
group by empno
order by 1
;
|
์ด๋, select ์ ์๋ group by ์ ์ ๊ธฐ์ ๋ ์ปฌ๋ผ(๋๋ ๊ฐ๊ณต์ปฌ๋ผ)์ด๋ ์ง๊ณ ํจ์๋ง ์ฌ ์ ์์ผ๋ฏ๋ก ์ง์ ์ด๋ฆ(ename)์ ๊ฐ์ ธ์ค๊ธฐ ์ํด์๋ ์ง๊ณ ํจ์ max()๋ฅผ ์ด์ฉํด์ผ ํ๋ค.
(์ฐธ๊ณ ) group by ๊ธฐ์ค ์ปฌ๋ผ์ด empno์ด๋ฏ๋ก ์ฐ๋ฆฌ๋ ํด๋น ์งํฉ์ด empno์ ๋ํด uniqueํ ์งํฉ์์ ์๊ณ ์๋ค. ๋ฐ๋ผ์ ์ง์ ์ด๋ฆ์ ๊ตฌํ๊ธฐ ์ํด ์์ฌํ๊ณ max()ํจ์๋ฅผ ์ธ ์ ์๋ค.
๋ง์ฝ ๊ทธ๋ฅ ename์ด๋ผ๊ณ ์ด ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
(์ค๋ฅ ๋ฉ์์ง) SQL Error [42803]: ERROR: column "temp.ename" must appear in the GROUP BY clause or be used in an aggregate function
4-3. ์ง๊ณ ํจ์ (Aggregate Function)์ count (distinct)์ ์ดํด
์ง๊ณ ํจ์ (Aggregate Function)
count(*)
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ๋ฐ์ดํฐ ๊ฑด์๋ฅผ ๊ฐ์ ธ์ด
count(distinct ์ปฌ๋ผ๋ช )
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ํด๋น ์ปฌ๋ผ์ผ๋ก ์ค๋ณต์ ๋ฐฐ์ ํ๊ณ ๊ณ ์ ํ ๊ฑด์๋ฅผ ๊ฐ์ ธ์ด
sum(์ปฌ๋ผ๋ช )
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ์ง์ ๋ ์ปฌ๋ผ๊ฐ์ ์ดํฉ์ ๊ฐ์ ธ์ด
min(์ปฌ๋ผ๋ช )
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ์ง์ ๋ ์ปฌ๋ผ๊ฐ์ ์ต์๊ฐ์ ๊ฐ์ ธ์ด
max(์ปฌ๋ผ๋ช )
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ์ง์ ๋ ์ปฌ๋ผ๊ฐ์ ์ต๋๊ฐ์ ๊ฐ์ ธ์ด
avg(์ปฌ๋ผ๋ช )
์ ํด์ง ์งํฉ ๋ ๋ฒจ์์ ์ง์ ๋ ์ปฌ๋ผ๊ฐ์ ํ๊ท ๊ฐ์ ๊ฐ์ ธ์ด
์ง๊ณ ํจ์ ์ ์ฉ ์ ์ ์ ์ฌํญ
1. ์ง๊ณ ํจ์๋ Null ์ ๊ณ์ฐํ์ง ์๋๋ค.
2. min, max ํจ์์ ๊ฒฝ์ฐ ์ซ์๊ฐ ๋ฟ๋ง ์๋๋ผ ๋ฌธ์์ด, ๋ ์ง/์๊ฐํ๋ ๊ฐ๋ฅํ๋ค.
4-4. ์ง๊ณ ํจ์ (Aggregate Function)์ count (distinct) ์ค์ต
์ค์ต ์์
์ค์ต์ฉ ํ ์ด๋ธ emp_test ์กฐํ
1
|
select *
from hr.emp_test order by deptno; |
1. comm ์ปฌ๋ผ์ ๋ํ ์ง๊ณ ํจ์ (aggregate function) ์ ์ฉ
1
2
3
4
|
select deptno, count(*) as cnt, sum(comm), max(comm), min(comm), avg(comm)
from hr.emp_test
group by deptno
order by deptno;
|
์ง๊ณ ํจ์๋ Null ์ ์ง๊ณํ์ง ์๋๋ค.
ํนํ ํ๊ท (avg)์ ๊ตฌํ ๋ ์ฃผ์ํด์ผ ํ๋ค.
๋ถ์ 30์ ๊ฒฝ์ฐ ์ ์ฒด ๊ฑด์์ธ count(*)๋ 6์ด์ง๋ง, comm ๊ฐ์ด Null ์ด ์๋ ๊ฑด์๋ 4์ด๋ค.
๋ฐ๋ผ์ avg(comm)๋ 2200 / 6 = 366.67 ์ด ์๋ 2200 / 4 = 550 ์ด ๋๋ค.
2. max, min ํจ์๋ ์ซ์๊ฐ๋ฟ๋ง ์๋๋ผ, ๋ฌธ์์ด, ๋ ์ง/์๊ฐ ํ์ ์๋ ์ ์ฉ ๊ฐ๋ฅ
1
2
3
4
|
select deptno, max(job), min(ename), max(hiredate), min(hiredate) --, sum(ename) --, avg(ename)
from hr.emp
group by deptno
order by deptno;
|
์ค์ ๊ฐ์ ๋ถ์ ๋ด์๋ ๋ค์ํ job, ename, hiredate ๊ฐ์ด ์กด์ฌํ์ง๋ง ๊ทธ ์ค์ ํ๋์ ๊ฐ๋ง ์ถ์ถํ๊ณ ์ถ์ ๋ max, min ํจ์๋ฅผ ์ด์ฉํ๋ค.
max ํจ์๋ฅผ ๋ฌธ์์ด์ ์ ์ฉํ๋ฉด ์ฒซ ๊ธ์์ ์ํ๋ฒณ ์์๊ฐ ๊ฐ์ฅ ๋ค์ ์๋ ๊ฐ์ ๊ฐ์ ธ์ค๋ฉฐ, ๋ ์ง์ ์ ์ฉํ๋ฉด ๊ฐ์ฅ ํฐ ๋ ์ง๊ฐ์ ๊ฐ์ ธ์จ๋ค.
min ํจ์๋ฅผ ๋ฌธ์์ด์ ์ ์ฉํ๋ฉด ์ฒซ ๊ธ์์ ์ํ๋ฒณ ์์๊ฐ ๊ฐ์ฅ ์์ ์๋ ๊ฐ์ ๊ฐ์ ธ์ค๋ฉฐ, ๋ ์ง์ ์ ์ฉํ๋ฉด ๊ฐ์ฅ ์์ ๋ ์ง๊ฐ์ ๊ฐ์ ธ์จ๋ค.
3. count(distinct ์ปฌ๋ผ๋ช )๋ ์ง์ ๋ ์ปฌ๋ผ๋ช ์ผ๋ก ์ค๋ณต์ ์ ๊ฑฐํ ๊ณ ์ ํ ๊ฑด์๋ฅผ ์ถ์ถ
1
|
select deptno, count(*) as cnt, count(distinct job)
from hr.emp_test group by deptno; |
์ค์ ๊ฐ ๋ถ์์ ๋ฐ์ดํฐ ๊ฑด์๋ 3, 4, 6๊ฑด์ด์ง๋ง job ์ปฌ๋ผ์ผ๋ก ์ค๋ณต์ ์ ์ธํ ๊ณ ์ ํ ๊ฑด์๋ฅผ ์ถ์ถํ๋ฉด ๊ฐ๊ฐ 3, 3, 3๊ฑด์ด ๋์จ๋ค.
์ด๋ฅผ ํตํด ๋ถ์ 10์๋ job ์ปฌ๋ผ์ ์ค๋ณต๋ ๋ฐ์ดํฐ๊ฐ ์๊ณ , ๋ถ์ 20์๋ 1๊ฑด, ๋ถ์ 30์๋ 3๊ฑด์ ์ค๋ณต๋ ๋ฐ์ดํฐ๊ฐ ์์์ ์ ์ ์๋ค.
4-5. Group By์ ์ ๊ฐ๊ณต ์ปฌ๋ผ ๋ฐ case when ์ ์ฉ ์ค์ต
Group By ์ ์๋ ํ ์ด๋ธ์ ์ ์๋ ์ปฌ๋ผ ๋ฟ๋ง ์๋๋ผ ๊ฐ๊ณต ์ปฌ๋ผ๋ ์ฌ ์ ์๋ค.
์ด๋ฅผ ํตํด ๋ ๋ค์ํ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋ฃนํํ ์ ์๋ค.
์ค์ต ์์ ๋ฅผ ํตํด ๋ ์์ธํ ์์๋ณด์.
์ค์ต ์์
1. 1000๋ฏธ๋ง, 1000-1999, 2000-2999์ ๊ฐ์ด 1000๋จ์ ๋ฒ์๋ด์ sal์ด ์๋ ๋ ๋ฒจ๋ก group by ํ๊ณ ํด๋น ๊ฑด์๋ฅผ ๊ตฌํจ
(๋์ ์๊ฐ)
1
2
3
4
|
select round(sal, -3) as sal_range, count(*) as cnt
from hr.emp
group by round(sal, -3)
order by round(sal, -3);
|
1000 ๋จ์ ๋ฒ์๋ก sal์ ๊ทธ๋ฃนํํ๋ ๋ฐฉ์์ด ์๊ฐ์ด ์ ๋์ ๋์ถฉ(?) round ํจ์๋ฅผ ์ผ๋๋ ๋ฐ์ดํฐ๊ฐ ์์ ์ด์ํ๊ฒ ๋ฌถ์ฌ๋ฒ๋ ธ๋ค.
round(sal, -3)์ sal ๋ฐ์ดํฐ๋ฅผ ์ ์ ์ธ๋ฒ์งธ ์๋ฆฌ์์ ๋ฐ์ฌ๋ฆผํด๋ฒ๋ฆฐ๋ค.
์๋ emp ํ ์ด๋ธ์ sal ๋ฐ์ดํฐ๋ฅผ ์ดํด๋ณด์.
sal ๊ฐ์ด 800, 950์ธ ๊ฒฝ์ฐ ์ ์ ์ธ๋ฒ์งธ ์๋ฆฌ์์ ๋ฐ์ฌ๋ฆผํ๋ฉด 1000์ด ๋๋ค.
1250, 1300์ธ ๊ฒฝ์ฐ์๋ ์ ์ ์ธ๋ฒ์งธ ์๋ฆฌ์์ ๋ฐ์ฌ๋ฆผํ๋ฉด 1000์ด ๋๋ค.
๋ฐ๋ผ์ ๋ด๊ฐ ์ผ๋ ๋ฐฉ์์ผ๋ก ๊ทธ๋ฃนํํ๋ฉด 1000 ๋ฏธ๋ง์ผ๋ก ๋ฌถ์ด๋ ๋ฐ์ดํฐ๋ ํ ๊ฑด๋ ๋์ค์ง ์๊ฒ ๋๋ค.
sal ์ปฌ๋ผ์ ๋ฐ์ดํฐ๋ฅผ 1000 ๋จ์๋ก ๊ทธ๋ฃนํํ๋ ค๋ฉด ์๋์ฒ๋ผ floor ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
(์ ๋ต)
1
2
3
4
|
select floor(sal/1000)*1000, count(*)
from hr.emp
group by floor(sal/1000)*1000
order by floor(sal/1000)*1000;
|
์ฐ์ sal/1000์ ํ ๊ฒฝ์ฐ, 0์ด์ 1000 ๋ฏธ๋ง์ ๊ฐ๋ค์ ๋ชจ๋ 0.xxx์ ๊ฐ์ด ๋์จ๋ค.
์ฌ๊ธฐ์ floor() ํจ์๋ฅผ ์ ์ฉํ์ฌ ์์์ ์ดํ ๊ฐ๋ค์ ๋ชจ๋ ๋ฒ๋ฆฌ๋ฉด 0์ด ๋๋ค.
0์ ๋ค์ 1000์ ๊ณฑํด๋ ๊ฒฐ๊ตญ 0์ด ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก sal/1000์ ํ ๊ฒฝ์ฐ, 1000 ์ด์ 2000 ๋ฏธ๋ง์ ๊ฐ๋ค์ ๋ชจ๋ 1.xxx์ ๊ฐ์ด ๋์จ๋ค.
์ฌ๊ธฐ์ floor() ํจ์๋ฅผ ์ ์ฉํ์ฌ ์์์ ์ดํ ๊ฐ๋ค์ ๋ชจ๋ ๋ฒ๋ฆฌ๋ฉด 1์ด ๋๋ฉฐ, ์ด ๊ฐ์ ๋ค์ 1000์ ๊ณฑํ๋ฉด 1000์ด ๋๋ค.
์ด๋ฐ ๋ฐฉ์์ผ๋ก 0 ์ด์ 1000 ๋ฏธ๋ง์ ๊ฐ๋ค์ 0์ผ๋ก, 1000 ์ด์ 2000 ๋ฏธ๋ง์ ๊ฐ๋ค์ 1000์ผ๋ก, (์๋ต), 5000 ์ด์ 6000 ์ดํ์ ๊ฐ๋ค์ 5000์ผ๋ก ๊ทธ๋ฃนํํ ์ ์๋ค.
๐ค postgreSQL์ ๋ฐ์ฌ๋ฆผ ๊ด๋ จ ํจ์๋ค
round(val [,n]) : ์ผ๋ฐ์ ์ธ ๋ฐ์ฌ๋ฆผ ํจ์
(์ฐธ๊ณ ) https://www.postgresqltutorial.com/postgresql-math-functions/postgresql-round/
PostgreSQL ROUND() Function By Practical Examples
The PostgreSQL ROUND() function rounds a numeric value to its nearest integer or a number with the number of decimal places. Syntax The following illustrates the syntax of the ROUND() function: ROUND (source [ , n ] )Code language: CSS (css) Arguments The
www.postgresqltutorial.com
ceil(numeric_expression) : ์ ๋ ฅ๊ฐ์ ํ๋๋ง ๋ฐ๋๋ค. ์์์ ์๋ ์ซ์๋ฅผ ๋ฌด์กฐ๊ฑด ์ฌ๋ฆฐ๋ค. ์ฒ์ฅ์ผ๋ก ๋ง๋ ๋ค๋ ์๋ฏธ์ด๋ค.
(์ฐธ๊ณ ) https://www.postgresqltutorial.com/postgresql-math-functions/postgresql-ceil/
PostgreSQL CEIL Function By Practical Examples
The PostgreSQL CEIL() function returns a number rounded up to the next whole number. Syntax The following illustrates the syntax of the CEIL() function: CEIL(numeric_expression) Arguments The CEIL() function requires one argument: 1) numeric_expression The
www.postgresqltutorial.com
floor(numeric_expression) : ์ ๋ ฅ๊ฐ์ ํ๋๋ง ๋ฐ๋๋ค. ์์์ ์๋ ์ซ์๋ฅผ ๋ฌด์กฐ๊ฑด ๋ฒ๋ฆฐ๋ค. ๋ฐ๋ฅ์ผ๋ก ๋ง๋ ๋ค๋ ์๋ฏธ์ด๋ค.
(์ฐธ๊ณ ) https://www.postgresqltutorial.com/postgresql-math-functions/postgresql-floor/
PostgreSQL FLOOR Function By Practical Examples
The PostgreSQL FLOOR() function returns a number rounded down to the next whole number. Syntax The syntax of the FLOOR() function is as follows: FLOOR(numeric_expression) Arguments The FLOOR() function requires one argument: 1) numeric_expression The numer
www.postgresqltutorial.com
2. job์ด SALESMAN์ธ ๊ฒฝ์ฐ์ ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ๋ง ๋๋์ด์ ํ๊ท /์ต์/์ต๋ ๊ธ์ฌ๋ฅผ ๊ตฌํ๊ธฐ
1
2
3
4
|
select case when job = 'SALESMAN' then 'SALESMAN' else 'OTHERS' end as job,
round(avg(sal),2) as avg_sal, min(sal) as min_sal, max(sal) as max_sal
from hr.emp
group by case when job = 'SALESMAN' then 'SALESMAN' else 'OTHERS' end;
|
case when์ select ์ ๋ฟ๋ง ์๋๋ผ where, group by, having ์ ์๋ ์ธ ์ ์๋ค.
๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ if ~ else ์ ๊ฐ์ ์ญํ ์ ํ๋ค.
์์ ์์์์๋ job์ด 'SALESMAN'์ธ ๊ฒฝ์ฐ๋ 'SALESMAN'์ผ๋ก, ๊ทธ ์ธ์๋ ๋ชจ๋ 'OTHERS'๋ก ๋๋๋๋ก ํ์ฌ ์ด๋ฅผ group by ์ ๊ณผ select ์ ์์ ์ฌ์ฉํ๋ค.
(์ฐธ๊ณ ) postgreSQL์ case๋ฌธ
https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-case/
PostgreSQL CASE
Summary: in this tutorial, you will learn how to use the PostgreSQL CASE conditional expression to form conditional queries. The PostgreSQL CASE expression is the same as IF/ELSE statement in other programming languages. It allows you to add if-else logic
www.postgresqltutorial.com
4-6. Group By์ ์ง๊ณ ํจ์์ case when์ ์ด์ฉํ ํผ๋ดํ ์ดํด
Group By ์ ํ ๋ ๋ฒจ๋ก ๋ง๋ค์ด์ง ๋ฐ์ดํฐ๋ฅผ ์ด ๋ ๋ฒจ๋ก ์ ํํ ๋, ์ง๊ณ ํจ์ (aggregate function)์ case when์ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ๋ค.
๋ณดํต ๊ฐ๋ ์ฑ์ ์ํด Pivoting ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
Pivoting ํ๋ฉด์ Group By์ ๋ ๋ฒจ์ Year + Month ์์ Year ๋ก ํ์ฅ๋์ง๋ง, select ์ ์์ ๋ค์ Month ๋จ์๋ก ์ชผ๊ฐ์ ๋ณด์ฌ์ฃผ๊ณ ์๋ค.
4-7. Group By์ ์ง๊ณ ํจ์์ case when์ ์ด์ฉํ ํผ๋ดํ ์ค์ต
์ค์ต ์์
1-1. deptno, job ๋ณ๋ก group byํ๊ณ ๊ฑด์ ๊ตฌํ๊ธฐ
1
2
3
4
|
select deptno, job, count(*) as cnt
from hr.emp
group by deptno, job
order by deptno, job;
|
์ํ ๊ฒฐ๊ณผ
1-2. group by Pivoting์ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฑด์ ๊ณ์ฐ ์ ํ(count case when then 1 else null end)
1
2
3
4
5
6
7
8
9
|
select deptno, count(*) as cnt
, count(case when job = 'SALESMAN' then 1 end) as salesman_cnt
, count(case when job = 'MANAGER' then 1 end) as manager_cnt
, count(case when job = 'ANALYST' then 1 end) as analyst_cnt
, count(case when job = 'CLERK' then 1 end) as clerk_cnt
, count(case when job = 'PRESIDENT' then 1 end) as president_cnt
from hr.emp
group by deptno
order by 1;
|
์ํ ๊ฒฐ๊ณผ
๊ฑด์ ๊ณ์ฐ์ ์ํด count() ํจ์๋ฅผ ์ฌ์ฉํ ๋ ์ ์ํ ์ ์ด ์๋ค.
๋ง์ฝ count() ํจ์ ๋ด์ case ๋ฌธ์์ else null ๋์ else 0์ ์ด๋ค๋ฉด ์ด๋ค ๊ฒฐ๊ณผ๊ฐ ๋์ฌ๊น?
1-3. group by Pivoting์ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฑด์ ๊ณ์ฐ์ ์๋ชป๋ ์ฌ๋ก(count case when then 1 else 0 end)
1
2
3
4
5
6
7
8
9
|
select deptno, count(*) as cnt
, count(case when job = 'SALESMAN' then 1 else 0 end) as sales_cnt
, count(case when job = 'MANAGER' then 1 else 0 end) as manager_cnt
, count(case when job = 'ANALYST' then 1 else 0 end) as analyst_cnt
, count(case when job = 'CLERK' then 1 else 0 end) as clerk_cnt
, count(case when job = 'PRESIDENT' then 1 else 0 end) as president_cnt
from emp
group by deptno
order by 1;
|
์ํ ๊ฒฐ๊ณผ
๋ชจ๋ ์ปฌ๋ผ์ ์ด ๊ฑด์๊ฐ ์ง๊ณ๋๋ค.
์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์์๊น?
count() ํจ์๋ ๊ฑด์๋ฅผ ์ ๋ 1์ 1๊ฑด์ผ๋ก, 0์ 0๊ฑด์ผ๋ก ์ธ๋ ๊ฒ์ด ์๋๋ผ null ์ด ์๋ ๋ชจ๋ ๊ฐ์ 1๊ฑด์ผ๋ก ์ธ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ count case when then 1 else null end ๋ฅผ ์ผ์ ๋์ count case when then 1 else 0 end ๋ฅผ ์ผ์ ๋์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅด๊ฒ ๋์จ๋ค.
(์ฐธ๊ณ ) case ๋ฌธ์์ else null ์ ์๋ตํ๊ณ case when then 1 end ๋ผ๊ณ ์ฐ๋ฉด ์์์ else null ๊ตฌ๋ฌธ์ผ๋ก ์ํ๋๋ค.
์์ 1-3 ์์์ ๊ฐ์ด else 0 ์ ์ฌ์ฉํ์ฌ ๊ฑด์๋ฅผ ์ง๊ณํ๊ณ ์ถ๋ค๋ฉด count() ํจ์ ๋์ sum() ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์๋ ์์๋ฅผ ํตํด sum() ํจ์๋ฅผ ์ด์ฉํ ๊ฑด์ ์ง๊ณ ์์๋ฅผ ์์๋ณด์.
1-4. group by Pivoting์ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฑด์ ๊ณ์ฐ์ sum()์ ์ด์ฉ
1
2
3
4
5
6
7
8
9
|
select deptno, count(*) as cnt
, sum(case when job = 'SALESMAN' then 1 else 0 end) as sales_cnt
, sum(case when job = 'MANAGER' then 1 else 0 end) as manager_cnt
, sum(case when job = 'ANALYST' then 1 else 0 end) as analyst_cnt
, sum(case when job = 'CLERK' then 1 else 0 end) as clerk_cnt
, sum(case when job = 'PRESIDENT' then 1 else 0 end) as president_cnt
from emp
group by deptno
order by 1;
|
์ํ ๊ฒฐ๊ณผ
4-8. Group By Rollup๊ณผ Group By Cube์ ์ดํด
Rollup ๊ณผ Cube ๋ Group By ์ ํจ๊ป ์ฌ์ฉ๋์ด Group By ์ ์ ์ฌ์ฉ๋๋ ์ปฌ๋ผ๋ค์ ๋ํด์ ์ถ๊ฐ์ ์ธ Group By ๋ฅผ ์ํํ๋ค.
Group By Rollup
Group By ์ Rollup ์ ํจ๊ป ์ฌ์ฉํ๋ฉด Rollup ์ ์ ์ฉ๋ ์ปฌ๋ผ์ ์์๋๋ก ๊ณ์ธต์ ์ธ Group By ๋ฅผ ์ถ๊ฐ ์ํํ๋ค.
(์์)
1
2
3
4
|
select deptno, job, sum(sal)
from hr.emp
group by rollup(deptno, job)
order by 1, 2;
|
Group By Cube
Group By ์ Cube ๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด Cube ์ ๋์ด๋ ์ปฌ๋ผ๋ค์ ๊ฐ๋ฅํ combination ์ผ๋ก Group By ๋ฅผ ์ํํ๋ค.
(์์)
1
2
3
4
|
select deptno, job, sum(sal) as sum
from hr.emp
group by cube(deptno, job)
order by 1, 2;
|
Group By Rollup๊ณผ Cube ์ ์ ์ฉ
Rollup(YEAR, MONTH, DAY)
YEAR, MONTH, DAY
YEAR, MONTH
YEAR
()
Group By Rollup ์ ์ ๋์ด๋ ์ปฌ๋ผ์๊ฐ N๊ฐ์ด๋ฉด Group By๋ N + 1 ํ ์ํ
Cube(YEAR, MONTH, DAY)
YEAR, MONTH, DAY
YEAR, MONTH
YEAR, DAY
YEAR
MONTH, DAY
MONTH
DAY
()
Group By Cube ์ ์ ๋์ด๋ ์ปฌ๋ผ์๊ฐ N๊ฐ์ด๋ฉด Group By๋ 2^n ํ ์ํ
4-9. Group By Rollup ์ค์ต
์ค์ต ์์
1. ๋ +์+์ผ๋ณ ๋งค์ถํฉ ๊ตฌํ๋, ์๋ณ ์๊ณ ๋งค์ถํฉ, ๋ ๋ณ ์๊ณ ๋งค์ถํฉ, ์ ์ฒด ๋งค์ถํฉ์ ํจ๊ป ๊ตฌํ๊ธฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
with
temp_01 as (
select to_char(b.order_date, 'yyyy') as year
, to_char(b.order_date, 'mm') as month
, to_char(b.order_date, 'dd') as day
, sum(a.amount) as sum_amount
from nw.order_items a
join nw.orders b on a.order_id = b.order_id
group by rollup(to_char(b.order_date, 'yyyy'), to_char(b.order_date, 'mm'), to_char(b.order_date, 'dd'))
)
select case when year is null then '์ด๋งค์ถ' else year end as year
, case when year is null then null
else case when month is null then '๋
์ด๋งค์ถ' else month end
end as month
, case when year is null or month is null then null
else case when day is null then '์ ์ด๋งค์ถ' else day end
end as day
, sum_amount
from temp_01
order by year, month, day
;
|
์์ ์์์์๋ Group By๊ฐ ์ด 3 + 1 = 4๋ฒ ์ํ๋๋ค.
4-10. Group By Cube ์ค์ต
Group By Cube ์ ๊ธฐ์ ๋ ์ปฌ๋ผ์ ๊ฐ๋ฅํ ๊ฒฐํฉ์ผ๋ก Group By๋ฅผ ์ํํ๋ค.
์ ๋ฌด์ ์ผ๋ก ํ์์๋ ์กฐํฉ์ผ๋ก ๊ทธ๋ฃนํํ๊ฑฐ๋ ๋๋ฌด ๋ง์ ์กฐํฉ์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ํ์ ์์ ์ค์ 3๊ฐ ์ด์ ์ปฌ๋ผ์ Group By Cube ๋ฅผ ์ํํ๋ ๊ฒฝ์ฐ๋ ๋๋ฌผ๋ค.
์ค์ต ์์
1. ์ํ ์นดํ ๊ณ ๋ฆฌ, ์ํ๋ณ, ์ฃผ๋ฌธ์ฒ๋ฆฌ์ง์๋ณ ๊ฐ๋ฅํ ๊ฒฐํฉ์ผ๋ก Group by ์ํ
1
2
3
4
5
6
7
8
|
select c.category_name, p.product_name, e.first_name || e.last_name as employee_name, sum(oi.amount) as sum_amount
from nw.order_items oi
join nw.orders o on oi.order_id = o.order_id
join nw.employees e on o.employee_id = e.employee_id
join nw.products p on oi.product_id = p.product_id
join nw.categories c on p.category_id = c.category_id
group by cube(c.category_name, p.product_name, e.first_name || e.last_name)
order by 1,2,3;
|
์์ ์์์์๋ Group By๊ฐ ์ด 2^3 = 8๋ฒ ์ํ๋๋ค.
'๐พ ๋ฐ์ดํฐ๋ฒ ์ด์ค > ๋ฐ์ดํฐ ๋ถ์ SQL Fundamentals' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ธ๋ก๊ทธ์ ์ ๋ณด
Claire's Study Note
Hi.Claire