데이터베이스 SQL 집계함수, 조인, 서브쿼리
내부 조인(inner join)
: 두 개의 테이블에 대해 조건에 일치되는 데이터만 가져오는 조인
select o.order_no, o.customer_no, product_no, order_quantity
from orders o
inner join order_details od on o.order_no = od.order_no;
employee, deapartment 테이블을 조인해서 각 직원의 이름과 부서명 출력
select e.name as 직원명, d.dept_name as 부서명
from employee e
inner join department d on e.Dept_no = d.dept_no;
외부 조인(Outer Join)
: 두 테이블에서 한쪽에는 데이터가 있고 한쪽에는 데이터가 없는 경우
데이터가 있는 테이블 기준으로 데이터를 출력
-> RIGHT / LEFT 외부조인
LEFT JOIN
RIGHT JOIN
문제 1-1.각 직원의 이름과 부서명을 조회하고, 직원이 없는 부서도 포함하여 조회
-> department 테이블을 기준으로 모든 부서의 정보를 표시하며, 해당 부서에 속한 직원의 이름도 함께 출력
만약 어떤 부서에 속한 직원이 없을 경우, 그 부서명은 여전히 출력되지만, 직원명은 NULL로 표시
select e.name as 직원명, d.dept_name as 부서명
from employee e
right join department d on e.Dept_no = d.dept_no;
문제 1-2. orders 테이블과 customer 테이블을 조인하여 각 주문의 고객명을 조회하세요.
select o.order_no, c.customer_comp_name as 고객명
from orders o inner join customer c
on o.customer_no = c.customer_no;
문제 1-4. 각 주문 상세의 제품 이름을 조회하세요.
select o.order_no, p.product_name
from order_details o inner join products p
on o.product_no = p.product_no;
문제 1-5. 재고가 0인 제품도 포함하여 각 주문 상세의 제품 이름을 조회하세요.
select o.order_no, p.product_name, p.inventory
from order_details o left join products p
on o.product_no = p.product_no;
문제 1-6. 각 주문의 고객명을 조회하세요.
select * from orders;
select * from customer;
select o.order_no, c.customer_comp_name as 고객명
from orders o left join customer c
on o.customer_no = c.customer_no;
문제 1-7. 각 주문을 처리한 직원의 이름을 조회하세요.
select o.order_no, e.name as 직원명
from orders o
left join employee e on o.Emp_no = e.Emp_no;
크로스조인 (Cross Join)
: 한쪽 테이블의 각 행마다 다른 쪽 테이블의 행이 모드 한번씩 각각 매칭
select p.product_name, d.dept_name
from products p
cross join department d;
select o.order_no, m1.grade_name
from orders o
cross join mileage_level m1;
셀프조인
: 동일한 테이블 내에서 한 컬럼이 다른 컬럼을 참조하는 조인
셀프조인을 하려면 조인 조건에 동일한 테이블명이 두 번 나타남
예제1. employee 테이블에서 직원, 상사 정보를 셀프조인으로 조회
select e1.name as 직원명, e2.name as 상사명
from employee e1
inner join employee e2 on e1.boss_number = e2.Emp_no;
예제2. 각 직원과 동일한 부서에 속한 다른 직원 정보 조회
select e1.name as 직원명, e2.name as 같은부서직원
from employee e1 inner join employee e2
on e1.Dept_no = e2.Dept_no
where e1.Emp_no <> e2.Emp_no;
문제1. 각 직원과 동일한 성별을 가진 다른 직원 정보를 조회하세요.
select e1.name as 직원명, e2.name as 같은성별직원
from employee e1
inner join employee e2 on e1.gender = e2.gender
where e1.emp_no <> e2.Emp_no;
문제2. employee 테이블에서 각 직원과 동일한 지역에 사는 다른 직원 정보를 조회하고 지역명도 함께 보이시오.
select e1.name as 직원명, e2.name as 동일지역직원, e1.area as 지역
from employee e1
inner join employee e2 on e1.area = e2.area;
문제 3-1. 특정 고객의 주문과 주문 상세를 조회하세요.
select o.order_no, od.product_no
from orders o, order_details od
where o.order_no = od.order_no and o.customer_no = 'CTUCA';
문제 3-2(응용문제). 각 주문에 대해 해당 주문의 고객 정보와 주문에 포함된 모든 제품의 정보(제품명, 단가)를 조회하되, 주문에 포함된 제품의 총 금액(수량 * 단가)을 계산하여 결과에 포함하세요.
응용문제 사용 테이블 : orders o, customer c, order_details od, products p
select o.order_no, c.customer_comp_name, p.product_name, p.unit_price, od.order_quantity
from orders o, customer c, order_details od, products p
where o.customer_no = c.customer_no and o.order_no = od.order_no and od.product_no = p.product_no;
응용문제 2. 각 직원의 상사 이름과 해당 직원이 처리한 주문의 총 금액을 조회하세요. 직원이 처리한 주문이 없는 경우도 포함하세요.
select e.name as 직원명, b.name as 심사명, coalesce(sum(od.order_quantity * p.unit_price))
from employee e
left join employee b on e.boss_number = b.Emp_no
left join orders o on e.emp_no = o.emp_no
left join order_details od on o.order_no = od.order_no
left join products p on od.product_no = p.product_no
group by e.name, b.name;
-> coalesce 함수 : 특정 값이 null 일 경우, 원하는 값으로 반환할시 사용
서브쿼리
컬럼 삽입 후 데이터 추가
# employee 테이블에 salary 추가
ALTER TABLE employee
ADD COLUMN salary DECIMAL(10, 2);
# 컬럼 삽입 후 데이터 추가
-- UPDATE employee
-- SET salary = CASE Emp_no
-- WHEN 'E01' THEN 42000.00
-- WHEN 'E02' THEN 73000.00
-- WHEN 'E03' THEN 43000.00
-- WHEN 'E04' THEN 40000.00
-- WHEN 'E05' THEN 52000.00
-- WHEN 'E06' THEN 48000.00
-- WHEN 'E07' THEN 38000.00
-- WHEN 'E08' THEN 65000.00
-- WHEN 'E09' THEN 62000.00
-- WHEN 'E10' THEN 32000.00
-- ELSE NULL
-- END;
서브쿼리 개념
: SQL문 내부에서 사용하는 SELECT문
사용 이유 -> 데이터 필터링, 집계 및 계산, 비교 및 검증, 중첩된 데이터 추출, EXIST절
- 단일 행 서브쿼리 : =, <, >
- 복수 행 서브쿼리 : IN, ALL, ANY, SOME, EXISTS
서브쿼리 예제1. 급여 가장 높게 받는 사람 누구인가
select Emp_no, name, salary from employee
where salary = (select max(salary) from employee);
서브쿼리 예제2. 특정 부서에서 가장 최근에 입사한 직원의 정보 조회
select emp_no, name, salary from employee
where date_of_emp = (select max(date_of_emp) from employee);
문제 1: 가장 많은 주문을 한 고객의 정보를 조회
select customer_no, customer_comp_name from customer
where customer_no = (select customer_no from orders group by customer_no order by count(*) DESC limit 1);
-> limit 1 : 가장 높은 값
문제 2: 특정 부서에서 가장 높은 연봉을 받는 직원의 정보를 조회
select emp_no, name, salary, dept_no from employee
where salary = (select max(salary) from employee where Dept_no = 'A1')
문제 3: 특정 제품을 가장 많이 주문한 고객의 정보를 조회
select customer_no, customer_comp_name from customer
where customer_no = (
select customer_no from orders o
join order_details od on o.order_no = od.order_no
where od.product_no = '1'
group by customer_no order by sum(od.order_quantity) DESC limit 1);
문제 4: 특정 부서에서 가장 많은 주문을 처리한 직원의 정보를 조회
select emp_no, name, dept_no, date_of_emp from employee
where emp_no = (
select emp_no from orders where emp_no in (select emp_no from employee where dept_no = 'A1')
group by emp_no order by count(*) DESC limit 1);
문제5: 가장 최근 입사한 직워다 먼저 입사한 직원 정보 조회
select emp_no, name, date_of_emp
from employee
where date_of_emp < (
select max(date_of_emp) from employee)
복수행 서브쿼리
문제1 : 가장 많이 주문한 제품 상위 3개를 주문한 고객들의 정보를 조회
select customer_no, customer_comp_name from customer
where customer_no in (
select customer_no from orders o
join order_details od on o.order_no = od.order_no
where od.product_no in(
select product_no from (
select product_no from order_details
group by product_no
order by sum(order_quantity) DESC limit 3) as top_products))
# 메인쿼리 : 서브 쿼리에서 반환된 고객 번호를 이용한 'customer' 테이블 내 해당 고객 정보 조회
select customer_no, customer_comp_name from customer
where customer_no in (
# sub query : 서브-서브 쿼리에서 반환된 상위 3개 제품번호를 사용해서, 'orders'와 'order_details' 테이블을 join
# 각 주문에 대한 고객 번호 반환
select customer_no from orders o
join order_details od on o.order_no = od.order_no
where od.product_no in(
# sub of sub query : 'order_details' 테이블에서 각 제품의 총 주문수량 계산, 상위 3개의 제품 번호를 선택
select product_no from (
select product_no from order_details
group by product_no
order by sum(order_quantity) DESC
limit 3) as top_products
)
)
-> 메인쿼리 : 서브쿼리에서 반환된 고객 번호를 이용한 'customer' 테이블 내 해당 고객 정보 조회
특정 제품을 주문한 고객들 중에서, 해당 제품을 주문한 모든 고객의 평균 주문 수량보다
더 많은 수량을 주문한 고객들의 정보를 조회
# 특정 제품을 주문한 고객들 중에서, 해당 제품을 주문한 모든 고객의 평균 주문 수량보다
# 더 많은 수량을 주문한 고객들의 정보를 조회
# 'customer' 테이블의 첫번째 서브쿼리에 대한 결과를 바탕으로 'customer_no'를 가진 고객 정보 조회
SELECT customer_no, customer_comp_name
FROM customer
WHERE customer_no IN (
# 각 고객의 총 주문수량을 확인(having)
# 'orders', 'order_details' 테이블을 조인하여 원하는 특정 제품을
# 주문한 각 고객의 주문번호 확인
SELECT customer_no
FROM orders o
JOIN order_details od ON o.order_no = od.order_no
WHERE od.product_no = '1'
GROUP BY customer_no
HAVING SUM(od.order_quantity) > (
SELECT AVG(total_quantity) # avg_quantity 서브쿼리 내 각 고객의 총 주문수량의 평균 계산
FROM (
# 'order', 'order_details' 테이블 조인하여, 특정 제품을 주문한 각 고객의 총 주문량 계산
# group by을 통해서 고객별 그룹화 진행 및 각 고객의 총 주문수량을 'total_quantity'로 계산
SELECT customer_no, SUM(order_quantity) AS total_quantity
FROM orders o
JOIN order_details od ON o.order_no = od.order_no
WHERE od.product_no = '1'
GROUP BY customer_no
) AS avg_quantities
)
);