
쿼리 안에 쿼리를 넣는 서브쿼리와, 이를 동일한 결과의 조인(JOIN)으로 변환하는 과정을 비교함.
평균값과 같이 집계된 결과를 조건으로 사용할 때 필수적임.
-- 1. 전체 평균 계란 무게 확인
select avg(egg_weight) from fms.chick_info;
-- 2. 평균보다 무거운 계란을 낳은 닭 조회 (서브쿼리)
select chick_no, egg_weight
from fms.chick_info
where egg_weight > (select avg(egg_weight) from fms.chick_info);
코드 테이블에서 명칭을 가져오는 등 단일 값을 매핑할 때 사용함.
-- 서브쿼리를 이용한 품종명 조회
select a.chick_no, a.breeds,
(
select m.code_desc
from fms.master_code m
where m.column_nm = 'breeds' and m.code = a.breeds
) as breeds_nm
from fms.chick_info a;
위의 스칼라 서브쿼리는 INNER JOIN으로 동일하게 구현 가능하며, 대량 데이터 처리 시 JOIN이 성능상 유리한 경우가 많음.
-- JOIN을 이용한 품종명 조회
select a.chick_no, a.breeds, b.code_desc as "breeds_nm"
from fms.chick_info a
inner join fms.master_code b
on a.breeds = b.code
where b.column_nm = 'breeds';
조회된 결과를 마치 테이블처럼 취급하여 조인함.
select a.chick_no, a.breeds, b.breeds_nm
from fms.chick_info a,
(
select code, code_desc as "breeds_nm"
from fms.master_code
where column_nm = 'breeds'
) b
where a.breeds = b.code;
복잡한 쿼리를 가상의 테이블로 저장하여 재사용함.
-- 뷰 생성
create or replace view fms.breeds_prod
(prod_date, breeds_nm, total_sum)
as
select a.prod_date,
(select m.code_desc from fms.master_code m where m.column_nm = 'breeds' and m.code = b.breeds),
sum(a.raw_weight)
from fms.prod_result a, fms.chick_info b
where a.chick_no = b.chick_no and a.pass_fail = 'P'
group by a.prod_date, b.breeds;
-- 뷰 조회
select * from fms.breeds_prod;
SELECT
TO_CHAR(prod_date, 'YYYYMM') AS prod_month,
SUM(CASE WHEN breeds_nm = 'Cornish' THEN total_sum else 0 END) AS Cornish_Total,
SUM(CASE WHEN breeds_nm = 'Cochin' THEN total_sum else 0 END) AS Cochin_Total,
SUM(CASE WHEN breeds_nm = 'Dorking' THEN total_sum else 0 END) AS Dorking_Total,
SUM(total_sum) AS monthly_total,
ROUND(
SUM(CASE WHEN breeds_nm = 'Cornish' THEN total_sum ELSE 0 END) * 100.0
/ NULLIF(SUM(total_sum), 0), 2
) || '%' AS cornish_rate
FROM fms.breeds_prod
GROUP BY TO_CHAR(prod_date, 'YYYYMM')
ORDER BY prod_month;
고객사별, 품종별 주문 및 출하 마릿수를 요약하는 뷰를 생성함.
CREATE OR REPLACE VIEW fms.daily_shipment_summary
( ship_date, customer_nm, breeds_nm, total_orders, total_chicks )
AS
SELECT
sh.arrival_date,
sh.customer,
ma.code_desc,
COUNT(sh.order_no) AS "total_orders",
COUNT(ch.chick_no) AS "total_chicks"
FROM fms.ship_result sh, fms.chick_info ch, fms.master_code ma
WHERE sh.chick_no = ch.chick_no
AND ch.breeds = ma.code
AND ma.column_nm = 'breeds'
GROUP BY sh.arrival_date, sh.customer, ma.code_desc
ORDER BY sh.arrival_date;
-- 특정 고객사('YESYES') 조회
select ship_date, breeds_nm, total_chicks
from fms.daily_shipment_summary
where customer_nm = 'YESYES';
기초 데이터 확인
select hatchday, gender, count(chick_no)::int as cnt
from fms.chick_info
group by hatchday, gender order by hatchday, gender;
CASE WHEN을 이용한 Pivot (표준)
select
a.hatchday,
sum(case when a.gender = 'M' then a.cnt else 0 end) as "Male",
sum(case when a.gender = 'F' then a.cnt else 0 end) as "Female"
from
(
select hatchday, gender, count(chick_no)::int as cnt
from fms.chick_info
group by hatchday, gender
) a
group by a.hatchday;
Crosstab을 이용한 Pivot (확장 기능)
create extension tablefunc;
select * from crosstab(
'select hatchday, gender, count(chick_no)::int from fms.chick_info group by 1, 2 order by 1, 2 DESC'
) as pivot_r(hatchday date, "Male" int, "Female" int);
기초 데이터 확인
select chick_no, body_temp, breath_rate, feed_intake
from fms.health_cond hc
where check_date = '2025-01-20' and chick_no like 'A%';
UNION을 이용한 Unpivot
select a.chick_no, a.health, a.cond
from
(
select chick_no, 'body_temp' as health, body_temp as cond
from fms.health_cond where check_date = '2025-01-20' and chick_no like 'A%'
union
select chick_no, 'breath_rate' as health, breath_rate as cond
from fms.health_cond where check_date = '2025-01-20' and chick_no like 'A%'
union
select chick_no, 'feed_intake' as health, feed_intake as cond
from fms.health_cond where check_date = '2025-01-20' and chick_no like 'A%'
) a
order by a.chick_no, a.health;
UNNEST를 이용한 Unpivot (배열 함수)
select
chick_no,
unnest(array['body_temp','breath_rate','feed_intake']) as health,
unnest(array[body_temp, breath_rate, feed_intake]) as cond
from fms.health_cond
where check_date = '2025-01-20' and chick_no like 'A%'
order by chick_no, health;
INSERT, UPDATE, DELETE 구문의 기본 구조와 실습임.
-- 기본 구조: INSERT INTO 테이블(컬럼) VALUES (값);
insert into fms.master_code(column_nm, type, code, code_desc)
values('breeds','txt','R1','Ross');
-- 여러 건 동시 추가
insert into fms.master_code(column_nm, type, code, code_desc)
values('breeds','txt','N1','New Hampshire Red'),
('breeds','txt','R2','Rhode Island Red'),
('breeds','txt','A1','Australorp');
-- 확인
select * from fms.master_code where column_nm = 'breeds';
-- 기본 구조: UPDATE 테이블 SET 컬럼=값 WHERE 조건;
update fms.master_code
set code_desc = '암컷'
where column_nm = 'gender' and code = 'F';
-- 확인
select * from fms.master_code where column_nm = 'gender';
-- 기본 구조: DELETE FROM 테이블 WHERE 조건;
delete from fms.master_code
where code = 'N1';
-- 트랜잭션 확정
commit;
자주 쓰는 로직을 함수로 정의하여 사용함.
CREATE FUNCTION [함수명]() RETURNS [반환타입] AS $$ [쿼리] $$ LANGUAGE [언어];
-- 전체 닭 마릿수를 반환하는 함수 생성
create function fms.get_chick_count()
returns integer
as $$
select count(*) from chick_info;
$$
language sql;
-- 함수 실행
select fms.get_chick_count();
select farm,
ROUND(COUNT(CASE WHEN pr.pass_fail = 'P' THEN 1 END) * 100.0
/ COUNT(ch.chick_no), 2) pass_rate
FROM fms.chick_info ch
JOIN fms.prod_result pr ON ch.chick_no = pr.chick_no
group by ch.farm;
select ch.chick_no, body_temp, farm
from fms.chick_info ch
join fms.health_cond he on ch.chick_no = he.chick_no
where he.body_temp > (select avg(body_temp) from fms.health_cond);
create view fms.view_farm_ship_summary
( farm, customer, shipped_count )
as
select ch.farm, sh.customer, count(sh.chick_no)
from fms.ship_result sh
join fms.prod_result pr on sh.chick_no = pr.chick_no
join fms.chick_info ch on ch.chick_no = sh.chick_no
group by ch.farm, sh.customer;
-- 뷰 확인 (농장 A만 조회)
select * from fms.view_farm_ship_summary where farm = 'A';
select a.prod_date,
sum(case when a.farm = 'A' then a.cnt else 0 end) as "Farm A",
sum(case when a.farm = 'B' then a.cnt else 0 end) as "Farm B",
sum(case when a.farm not in ('A', 'B') then a.cnt else 0 end) as "Farm C"
from
(
select pr.prod_date, ch.farm, count(ch.chick_no)::int as cnt
from fms.prod_result pr
join fms.chick_info ch on ch.chick_no = pr.chick_no
group by pr.prod_date, ch.farm
) a
group by a.prod_date
order by a.prod_date;
