-----------과제 내용-----------
1. 온라인푸드마켓을 위해 아래와 같은 DB를 구축한다.
물품에 대한 정보는 물품ID, 물품명, 분류, 가격, 평점, 재고 등을 기록한다.
물품의 분류는 곡류, 채소, 과일, 고기이다.
고객은 장바구니를 만들어 필요한 물품과 수량을 담으며, 장바구니에 포함되는 물품의 개수는 제한이 없다.
장바구니는 각각 품목에 대한 금액과 전체 품목에 대한 총액을 표시한다.
구매가 확정된 장바구니는 구매날짜를 저장하고, 추후 포함된 물품의 일부 또는 전부를 환불할 수 있다.
고객은 처음 가입 시 고객ID, 이름, 주소, 전화번호를 입력한다.
구매한 물품에 대해 평점(1~5)과 리뷰를 입력하면 입력건당 1점의 포인트를 부여하고, 포인트 3점 당 1000원 할인권을 부여한다. 고객은 물품 구매시 할인권을 사용할 수 있다.
2. 이러한 DB를 다음과 같은 순서로 설계하시오
① ER Diagram
② Database Schema (테이블 구조)
③ 샘플 데이터 입력(고객 5명, 물품 20개(각 분류당 5개 이상), 장바구니 10개 생성(빈 장바구니 1개, 1개 물품 포함 장바구니 2개, 나머지 3개 이상 물품 포함) 후 8개 구입(할인권 사용 2회 이상), 전체 구매 물품 환불 2건, 구매 물품 중 일부 환불 2건, 평점및리뷰 20건)
* 데이터 입력은 Insert 문이나 프로시저를 이용하고, 입력과정에 사용된 모든 script를 보고서에 포함하고, 위에 제시된 조건을 만족하는지 설명하시오
3. 정규화
위에서 설계된 각 테이블을 정규화하시오(4NF임을 설명)
4. 작성된 DB에 대해 아래 각 질문에 답하시오 (PL/SQL 프로그램 소스 및 결과 포함)
① 물품을 검색하는 procedure를 생성하시오. 이 프로시저는 분류명을 입력매개변수로 받아(즉, 곡류, 채소, 과일, 고기) 해당 분류에 포함되는 각 물품의 물품ID, 물품명, 가격, 평점, 재고, 그리고 고객이 작성한 모든 리뷰를 출력한다.
이 procedure를 이용하여 곡류, 채소, 과일, 고기에 포함되는 물품을 검색하시오.
② 고객을 검색하는 procedure를 생성하시오. 이 프로시저는 고객ID를 입력매개변수로 받아 해당 고객의 이름, 주소, 전화번호, 보유할인권액수, 구매 내역, 구매하지 않은 장바구니 내역, 환불 내역, 작성한 모든 리뷰와 평점을 출력한다.
이 프로시저를 이용하여 고객 3명을 검색하시오.
③ 재고관리를 위해 각 물품의 재고가 5개 미만으로 내려가면 물품주문목록에 해당 물품을 5개 입력하는 Trigger를 작성하시오(재고 5개 이상에서 5개 미만으로 변할 때 1회 실행)
고객의 구매를 실행하여 재고가 5에서 4로 변할때 이 Trigger가 실행 되고, 재고가 4에서 3으로 변할때는 실행되지 않음을 설명하시오
④ 주문할 물품이 포함된 물품주문목록의 물품이 입고 되었다고 가정하여, 물품의 재고를 수정하고 물품주문목록을 비우는 procedure를 작성하시오.
이 프로시저를 실행한 후 재고량과 물품주문목록의 변화를 설명하시오
⑤ 각 고객에 대해 물품을 추천하는 procedure를 생성하시오. 이 프로시저는 고객ID를 입력매개변수로 받아 고객이 구매한적이 있는 분류에 속하는 물품 중 평점이 높은 물품 5개를 추천하는데, 각 물품에 대해 물품ID, 물품명, 가격, 평점, 재고, 그리고 고객이 작성한 모든 리뷰를 출력한다.
고객 2명에 대한 물품 추천을 실행하시오
⑥ 고객의 구입내역을 분류별로 합산하여 출력하시오. 이때 환불된 것은 제외한다.
고객ID | 곡류 | 채소 | 과일 | 고기 | 총액 |
…… | |||||
…… |
5. 문제에서 지정하지 않은 내용은 각자의 방법으로 구현하고
모든 결과를 하나의 보고서로 작성하여 Iclass로 제출 (보고서는 문제의 순서대로 작성)
6. 주의사항
① MS Word와 PDF외 다른 파일 포맷은 최대 0점 처리 (zip, hwp, txt, jpg 등)
② 다른 학생의 과제와 유사한 부분이 있을 경우 최대 0점 처리
③ 4번의 ⑥만 결과가 테이블이고 다른 문제의 결과는 테이블이 아닌 자유형태이다
----과제 구현 결과---
E-R Diagram
Scheme
create table product(
p_id int not null,
name varchar(20) not null,
class varchar(6) not null check (class in ('곡류','채소','과일','고기')),
price int not null,
avg_rate numeric(10,5),
remain int,
primary key (p_id)
);
create table customer(
c_id int not null,
name varchar(20) not null,
address varchar(50),
phone varchar(15),
point int,
primary key(c_id)
);
create table cart_list(
cart_id int not null,
c_id int,
primary key(cart_id),
foreign key(c_id) references customer(c_id)
);
create table cart(
cart_id int not null,
p_id int,
quantity int check(quantity>=0),
foreign key (p_id) references product(p_id),
foreign key (cart_id) references cart_list(cart_id)
);
create table completed(
p_id int not null,
c_id int not null,
quantity int not null check(quantity>=0),
rate int not null check(rate between 1 and 5),
complete_date varchar(10) not null,
review long,
discounted int,
foreign key (p_id) references product(p_id) on delete cascade,
foreign key (c_id) references customer(c_id) on delete cascade
);
create table refund(
p_id int not null,
c_id int not null,
quantity int not null check(quantity>=0),
complete_date varchar(10) not null,
refund_date varchar(10) not null,
foreign key (p_id) references product(p_id) on delete cascade,
foreign key (c_id) references customer(c_id) on delete cascade
);
create table ordertable(
p_id int not null,
addquantity int not null,
foreign key (p_id) references product(p_id) on delete cascade
);
구매 확정 및 환불 기능 프로시저
--cartid 카트의 어떤 한 품목pid에 대해 구매를 확정
create or replace procedure confirmpurchase(cartid in int,pid in int, xrate in int,xdate in varchar,xreview in long,xdiscounted in int)
is
productremain int;
requestcnt int;
targetcustomerid int;
couponcnt int;
begin
select remain into productremain from product where product.p_id = pid;
select quantity into requestcnt from cart where cart.p_id = pid and cart.cart_id = cartid;
select distinct cart_list.c_id into targetcustomerid from cart_list,customer where cart_list.cart_id = cartid; --장바구니를 가지고 있는 손님 아이디 찾기--
select (point/3) into couponcnt from customer where customer.c_id = targetcustomerid;
dbms_output.put_line('구매 실행');
if (xdiscounted = 1 and couponcnt = 0) then
dbms_output.put_line('쿠폰 없음');
return;
end if;
if productremain < requestcnt then
dbms_output.put_line('재고 부족');
return; --구매할수량이 재고보다 작으면 끝내--
end if;
update product set product.remain = product.remain - requestcnt where product.p_id = pid;
delete from cart where cart.cart_id = cartid and cart.p_id = pid;
insert into completed(p_id,c_id,quantity,rate,complete_date,review,discounted) values(pid,targetcustomerid,requestcnt,xrate,xdate,xreview,xdiscounted);
update product
set avg_rate = (select avg(rate) from completed c_item where c_item.p_id = product.p_id)
where product.p_id = pid;
update customer
set customer.point = customer.point + 1 where customer.c_id = targetcustomerid;
if xdiscounted = 1 then
update customer
set customer.point = customer.point - 3 where customer.c_id = targetcustomerid;
end if;
return;
end;
/
--cid 손님이 pid 품목을 xquan만큼 xdate에 산걸 환불요청함--
create or replace procedure dorefund(pid in int,cid in int,xquan in int,xdate in varchar,rdate in varchar)
is
purchasecnt int;
begin
select quantity into purchasecnt from completed where completed.p_id = pid and completed.c_id = cid and completed.complete_date = xdate;
if purchasecnt < xquan then
dbms_output.put_line('구매 수량보다 더 많이 요청함');
return;
end if;
update completed set completed.quantity = completed.quantity - xquan where completed.p_id = pid and completed.c_id = cid and completed.complete_date = xdate;
update product set product.remain = product.remain + xquan where product.p_id = pid;
--만약 전액 환불 했으면 리뷰 지우고 completed에서도 지움--
if purchasecnt = xquan then
delete from completed where completed.p_id =pid and completed.c_id = cid and completed.complete_date = xdate;
end if;
--refund 테이블에 환불 기록 남기기--
insert into refund(p_id,c_id,quantity,complete_date,refund_date) values(pid,cid,xquan,xdate,rdate);
end;
샘플 데이터 입력
insert into customer(c_id,name,address,phone,point)
values(1000,'김민석','대구광역시 수성구 달구벌대로 3310','01040306453',0);
insert into customer(c_id,name,address,phone,point)
values(2000,'김상우','서울 남산타워뷰 보이는 어딘가','01012345678',0);
insert into customer(c_id,name,address,phone,point)
values(3000,'최지원','중국 어딘가','01087654321',0);
insert into customer(c_id,name,address,phone,point)
values(4000,'오상연','인천광역시 미추홀구 학익동 어딘가','010192345394',0);
insert into customer(c_id,name,address,phone,point)
values(5000,'전예준','8군단 22사단 해안감시대 소초 어느곳','01011111111',0);
insert into product(p_id,name,class,price,avg_rate,remain)
values(1,'쌀','곡류',40000,0,10);
insert into product(p_id,name,class,price,avg_rate,remain)
values(2,'보리','곡류',50000,0,50);
insert into product(p_id,name,class,price,avg_rate,remain)
values(3,'옥수수','곡류',10000,0,30);
insert into product(p_id,name,class,price,avg_rate,remain)
values(4,'조','곡류',20000,0,20);
insert into product(p_id,name,class,price,avg_rate,remain)
values(5,'콩','곡류',5000,0,50);
insert into product(p_id,name,class,price,avg_rate,remain)
values(6,'청경채','채소',3000,0,100);
insert into product(p_id,name,class,price,avg_rate,remain)
values(7,'양상추','채소',2000,0,300);
insert into product(p_id,name,class,price,avg_rate,remain)
values(8,'치커리','채소',5000,0,100);
insert into product(p_id,name,class,price,avg_rate,remain)
values(9,'부추','채소',1000,0,500);
insert into product(p_id,name,class,price,avg_rate,remain)
values(10,'배추','채소',7000,0,1000);
insert into product(p_id,name,class,price,avg_rate,remain)
values(11,'사과','과일',2000,0,100);
insert into product(p_id,name,class,price,avg_rate,remain)
values(12,'배','과일',3000,0,100);
insert into product(p_id,name,class,price,avg_rate,remain)
values(13,'수박','과일',20000,0,50);
insert into product(p_id,name,class,price,avg_rate,remain)
values(14,'바나나','과일',4000,0,70);
insert into product(p_id,name,class,price,avg_rate,remain)
values(15,'포도','과일',3000,0,100);
insert into product(p_id,name,class,price,avg_rate,remain)
values(16,'돼지','고기',2000,0,1000);
insert into product(p_id,name,class,price,avg_rate,remain)
values(17,'소','고기',4000,0,1000);
insert into product(p_id,name,class,price,avg_rate,remain)
values(18,'닭','고기',7000,0,500);
insert into product(p_id,name,class,price,avg_rate,remain)
values(19,'양','고기',6000,0,1000);
insert into product(p_id,name,class,price,avg_rate,remain)
values(20,'악어','고기',40000,0,10);
--장바구니 10개 생성--
insert into cart_list(cart_id,c_id) values(1,1000);
insert into cart_list(cart_id,c_id) values(2,1000);
insert into cart_list(cart_id,c_id) values(3,2000);
insert into cart_list(cart_id,c_id) values(4,2000);
insert into cart_list(cart_id,c_id) values(5,2000);
insert into cart_list(cart_id,c_id) values(6,3000);
insert into cart_list(cart_id,c_id) values(7,3000);
insert into cart_list(cart_id,c_id) values(8,4000);
insert into cart_list(cart_id,c_id) values(9,4000);
insert into cart_list(cart_id,c_id) values(10,5000);
--장바구니에 물품 넣기 10번은 빈바구니로 두겠다 1,2번은 1개 물품 포함 나머지는 3개 이상--
insert into cart(cart_id,p_id,quantity) values(1,1,5);
insert into cart(cart_id,p_id,quantity) values(2,2,5);
insert into cart(cart_id,p_id,quantity) values(3,3,7);
insert into cart(cart_id,p_id,quantity) values(3,4,5);
insert into cart(cart_id,p_id,quantity) values(3,5,1);
insert into cart(cart_id,p_id,quantity) values(4,6,10);
insert into cart(cart_id,p_id,quantity) values(4,8,39);
insert into cart(cart_id,p_id,quantity) values(4,10,5);
insert into cart(cart_id,p_id,quantity) values(5,9,5);
insert into cart(cart_id,p_id,quantity) values(5,11,5);
insert into cart(cart_id,p_id,quantity) values(5,14,35);
insert into cart(cart_id,p_id,quantity) values(5,15,50);
insert into cart(cart_id,p_id,quantity) values(6,16,50);
insert into cart(cart_id,p_id,quantity) values(6,17,50);
insert into cart(cart_id,p_id,quantity) values(6,18,50);
insert into cart(cart_id,p_id,quantity) values(6,19,30);
insert into cart(cart_id,p_id,quantity) values(6,20,5);
insert into cart(cart_id,p_id,quantity) values(6,1,5);
insert into cart(cart_id,p_id,quantity) values(7,11,50);
insert into cart(cart_id,p_id,quantity) values(7,13,2);
insert into cart(cart_id,p_id,quantity) values(7,14,4);
insert into cart(cart_id,p_id,quantity) values(7,16,30);
insert into cart(cart_id,p_id,quantity) values(7,12,5);
insert into cart(cart_id,p_id,quantity) values(7,1,5);
insert into cart(cart_id,p_id,quantity) values(8,7,10);
insert into cart(cart_id,p_id,quantity) values(8,8,9);
insert into cart(cart_id,p_id,quantity) values(8,12,5);
insert into cart(cart_id,p_id,quantity) values(9,12,10);
insert into cart(cart_id,p_id,quantity) values(9,11,5);
insert into cart(cart_id,p_id,quantity) values(9,19,5);
exec confirmpurchase(6,16,5,'20220605','품질이 좋음1',0);
exec confirmpurchase(6,17,4,'20220615','품질이 좋음2',0);
exec confirmpurchase(6,18,3,'20220610','품질이 좋음3',0);
exec confirmpurchase(7,11,2,'20220625','품질이 좋음4',0);
exec confirmpurchase(7,13,3,'20220615','품질이 좋음5',0);
exec confirmpurchase(7,14,2,'20220613','품질이 좋음6',0);
exec confirmpurchase(6,20,1,'20220612','품질이 좋음7',1);
exec confirmpurchase(7,12,4,'20220619','품질이 좋음8',1);
exec confirmpurchase(4,6,1,'20220610','품질이 좋음9',0);
exec confirmpurchase(5,9,2,'20220610','품질이 좋음10',0);
exec confirmpurchase(3,3,5,'20220610','품질이 좋음11',0);--
exec confirmpurchase(6,19,4,'20220610','품질이 좋음12',0);
exec confirmpurchase(6,1,2,'20220610','품질이 좋음13',0);
exec confirmpurchase(7,1,3,'20220610','품질이 좋음14',0);
exec confirmpurchase(8,12,1,'20220610','품질이 좋음15',0);
exec confirmpurchase(8,8,5,'20220610','품질이 좋음16',0);
exec confirmpurchase(8,7,3,'20220610','품질이 좋음17',0);
exec confirmpurchase(2,2,1,'20220610','품질이 좋음18',0);--
exec confirmpurchase(9,11,1,'20220610','품질이 좋음19',0);
exec confirmpurchase(9,19,4,'20220610','품질이 좋음20',0);
exec dorefund(1,1000,2,'20220610','20220615');
exec dorefund(16,3000,5,'20220605','20220615');
exec dorefund(3,2000,5,'20220610','20220615');
exec dorefund(2,1000,1,'20220605','20220615');
3. 정규화 설명
-product(p_id,name,class,price,avg_rate,remain)
p_id -> 나머지 모든 속성이고 다중값이 없기 때문에 정규화됨
-customer(c_id,name,address,phone,point)
c_id -> 나머지 모든 속성이고 다중값이 없음.
-cart_list(cart_id,c_id)
cart_id -> c_id 이고 cart_id가 primary key임. 다중속성 허용하지 않음
-cart(cart_id,p_id,quantity)
cart_id -> p_id,quantity 이고 cart_id가 superkey임
-completed(p_id,c_id,quantity,rate,complete_date,review,discounted)
(p_id,c_id,quantity,rate,complete_date,review,discounted) 의 쌍이 키이고 각 상황에 따라 모든 값이 유일해 질 수 있음. 독립적일 수 있음(같은날이라도 수량을 다르게 여러번 살 수 있고 별점을 다르게 메길 수 있음, 같은 품목을 같은 사람이 ..모든 조건이 같아도 다른 날 살 수 있음. 모든 조건이 같아도 리뷰를 다르게 여러번 쓸 수 있음. 같은 날 같은 품목을 사도 할인을 적용 할 수도 안 할 수도 있음)
-refund(p_id,c_id,quantity,complete_date,refund_date)
위와 같이 모든 속성들이 독립적일 수 있기 때문에 모든 값이 유일할 수 있다.
-ordertable(p_id,addquantity)
p_id->addquantity이고 p_id가 primary key이며 addquantity값은 다중값을 가지지 않는다.
4.1번
--4.1번 찾기--
create or replace procedure searchprod(cl in varchar)
as
cursor c1 is select product.p_id,name,price,avg_rate,remain,review from product,completed where class = cl and product.p_id = completed.p_id;
begin
for res in c1
loop
dbms_output.put_line(rpad(res.p_id,4)||rpad(res.name,10)||rpad(res.price,7)||rpad(res.avg_rate,4)||rpad(res.remain,5)||res.review);
end loop;
end;
4.2번
create or replace procedure searchcustomer(cid in int)
as
cursor c1 is select name,address,phone,trunc(point/3) as coupon from customer where customer.c_id = cid; --고객정보
cursor c2 is select product.p_id,product.name,completed.quantity,completed.complete_date from completed,customer,product --구매내역
where completed.c_id = customer.c_id and completed.p_id = product.p_id and completed.c_id = cid;
cursor c3 is select product.p_id,product.name,refund.refund_date,refund.quantity from refund,customer,product --환불내역
where refund.c_id = customer.c_id and refund.p_id = product.p_id and refund.c_id = cid;
cursor c4 is select product.p_id,product.name,completed.review from completed,product --리뷰내역
where completed.p_id = product.p_id and completed.c_id = cid;
begin
dbms_output.put_line('고객 검색 결과:');
for res1 in c1
loop
dbms_output.put_line('이름 : '||res1.name||' 주소 : '||res1.address||' 전화번호 : '||res1.phone||' 사용가능한 쿠폰수 : '||res1.coupon);
end loop;
dbms_output.put_line('고객 구매 내역 : ');
dbms_output.put_line(rpad('품목id',6)||rpad('품목명',20)||rpad('수량',5)||rpad('구매날짜',12));
for res2 in c2
loop
dbms_output.put_line(rpad(res2.p_id,6)||rpad(res2.name,20)||rpad(res2.quantity,5)||rpad(res2.complete_date,12));
end loop;
dbms_output.put_line('환불 내역 : ');
dbms_output.put_line(rpad('품목id',6)||rpad('품목명',20)||rpad('환불날짜',12)||rpad('수량',5));
for res3 in c3
loop
dbms_output.put_line(rpad(res3.p_id,6)||rpad(res3.name,20)||rpad(res3.refund_date,12)||rpad(res3.quantity,5));
end loop;
for res4 in c4
loop
dbms_output.put_line(rpad(res4.p_id,6)||rpad(res4.name,20));
dbms_output.put_line(res4.review);
end loop;
end;
쿠폰 같은 경우는, 리뷰 한번 작성할 때 마다 point가 1이 올라간다. 하지만 손님이 보는 입장에서는 point/3 (소수점 truncate)값을 본다(실질적인 쿠폰 수)
4.3번
--4.3번 5개 미만으로 내려갈 때 Trigger--
create or replace trigger on_scarce after update on product
for each row
declare
x_exist int;
begin
select count(*) into x_exist from ordertable where ordertable.p_id = :new.p_id;
if x_exist = 0 and :new.remain < 5 then
insert into ordertable(p_id,addquantity) values(:new.p_id,5);
end if;
end;
처음 재고가 5개 미만으로 내려갔을 때, ordertable에 해당 p_id 값에 addquantity 5를 추가한다. 다음 5개 미만으로 내려갔을 때, ordertable에 이미 해당 p_id값이 있기 때문에 , 추가 주문 없이 그대로 trigger를 빠져나온다.
4.4번
--4.4번 물품주문목록 비우기--
create or replace procedure onaddcompleted
as
cursor c1 is select p_id,addquantity from ordertable;
begin
for res in c1
loop
update product set product.remain = product.remain + res.addquantity where product.p_id = res.p_id;
end loop;
delete from ordertable;
end;
이 프로시저는 호출하면 ordertable에 있는 row들을 순회한다. 각 row를 순회할 때 product 테이블의 p_id entity를 찾아서 addquantity만큼 수량을 plus해준다(기본 5)
모든 작업이 끝난 후에는 ordertable을 싹 비워준다.
4.5번
--4.5번 추천 물품
create or replace procedure recommend(cid in int)
as
cursor cc1 is select p1.p_id,p1.name,p1.price,p1.avg_rate,p1.remain from (select * from (select distinct product.p_id,product.name,product.price,product.avg_rate,product.remain,rank() over (order by product.avg_rate)
as rate_rank from completed,product where completed.c_id = cid and product.p_id = completed.p_id) where rate_rank <= 5 order by rate_rank) p1,completed where p1.p_id = completed.p_id;
begin
dbms_output.put_line('고객님께 추천드리는 목록');
for res in cc1
loop
dbms_output.put_line(rpad(res.p_id,6)||rpad(res.name,20)||rpad(res.price,7)||rpad(res.avg_rate,6)||rpad(res.remain,5));
for c_list in (select completed.review from product,completed where product.p_id = completed.p_id and product.p_id = res.p_id)
loop
dbms_output.put_line(c_list.review);
end loop;
end loop;
end;
4.6번
--4.6번 합산--
create or replace procedure sumbyclass
is
x_sum int;
x_cnt int;
begin
dbms_output.put_line('고객님들께서 구매하신 목록');
dbms_output.put_line(rpad('고객id',7)||rpad('곡류',10)||rpad('채소',10)||rpad('과일',10)||rpad('고기',10)||rpad('총액',10));
for res1 in (select c_id from customer)
loop
x_sum := 0;
dbms_output.put(rpad(res1.c_id,7));
select count(class) into x_cnt from (select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='곡류';
if x_cnt = 0 then
dbms_output.put(rpad('0',10));
end if;
for res2 in (select sop from(select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='곡류')
loop
dbms_output.put(rpad(res2.sop,10));
x_sum := x_sum + res2.sop;
end loop;
select count(class) into x_cnt from (select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='채소';
if x_cnt = 0 then
dbms_output.put(rpad('0',10));
end if;
for res2 in (select sop from(select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='채소')
loop
dbms_output.put(rpad(res2.sop,10));
x_sum := x_sum + res2.sop;
end loop;
select count(class) into x_cnt from (select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='과일';
if x_cnt = 0 then
dbms_output.put(rpad('0',10));
end if;
for res2 in (select sop from(select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='과일')
loop
dbms_output.put(rpad(res2.sop,10));
x_sum := x_sum + res2.sop;
end loop;
select count(class) into x_cnt from (select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='고기';
if x_cnt = 0 then
dbms_output.put(rpad('0',10));
end if;
for res2 in (select sop from(select sum(price*quantity) as sop,class from completed,product where completed.p_id = product.p_id and completed.c_id = res1.c_id group by class) where class='고기')
loop
dbms_output.put(rpad(res2.sop,10));
x_sum := x_sum + res2.sop;
end loop;
dbms_output.put(x_sum);
dbms_output.put_line('');
end loop;
end;