유정잉

19일차 MySQL [ view, 스토어드 프로시저, 트리거 ] 본문

네이버 클라우드 부트캠프/복습 정리

19일차 MySQL [ view, 스토어드 프로시저, 트리거 ]

유정♡ 2024. 3. 18. 16:41
조인, 프로시저, 트리거가 제일 중요 !!!

데이터 모델링도 중요 !!! (엔티티, 속성, 관계)

 

[ 뷰, view : 가상테이블 ]

    - 저장창치 내에서 물리적으로 존재하지 않는다. 사용자에게는 있는 것 처럼 간주된다.

    - 임시작업에서 사용된다. ( 그 이후에는 사용 되지 않음 )

  

[ 뷰생성 ( 임시적인 사용 ) ]

    CREATE VIEW v_student1 AS SELECT * FROM student  WHERE stu_dept='컴퓨터정보'; 

        
    DESC v_student1; -- v_student1 뷰테이블 생성 확인


    SELECT * FROM v_student1;  -- v_student1 뷰테이블 모든 정보 불러오기 -> 확인


   create view v_emp20 as select *from emp where deptno=20;
       -- 사원테이블로부터 20번 부서의 사원들로 이루어져 있는 뷰를 생성하라(v_emp20)

 

 [ 뷰 조인 ]
    create view v_enrol1 as select b.sub_name, a.sub_no, stu_no, enr_grade from enrol a, subject b

    where a.sub_no=b.sub_no;


    select *from v_enrol1;

 

    create view v_emp_dept as select empno, ename, dname from dept,emp where emp.deptno=dept.deptno;
       --  사원번호, 사원이름, 부서이름을 가지는 뷰(v_emp_dept)를 생성하라


     drop view v_emp_dept;


[ top n 질의 ] : 상위 n개의 데이터를 추출하는 쿼리

   SELECT stu_no, stu_name, stu_height FROM (SELECT stu_no, stu_name, stu_height FROM student
   WHERE stu_height is not null ORDER BY stu_height desc LIMIT 5) as sub;

      -- 만약 as로 별명을 붙이지 않으면 오류 !! , null일 경우 출력하면 안 됨 !! is not null 사용하기 !!!

 

   SELECT empno, ename, hiredate FROM (SELECT empno, ename, hiredate FROM emp
   WHERE hiredate is not null ORDER BY hiredate DESC LIMIT 3) as curent;

       -- 가장 최근에 입사한 3명 사원번호, 사원이름, 입사일

   SELECT empno, ename, hiredate FROM emp WHERE hiredate is not null ORDER BY hiredate DESC LIMIT 3;

      -- as가 없다면 구냥 이런식으로 해도 됨 !!! 위에꺼랑 똑같지만 as로 별명줄경우 안 줄경우임 ~SELECT dname
   FROM (SELECT dname, avg(sal) FROM emp JOIN dept ON dept.deptno=emp.deptno
   GROUP BY dname, sal ORDER BY 2 DESC LIMIT 2) as hi;

      -- 부서별 평균 급여가 가장 큰 부서 2개의 부서이름 검색

 


[ 스토어드 프로시저(Stored Procedure) ]

  - 저장 프로시저라고도 불린다. MySQL에서 제공되는 프로그래밍 기능이다.

  - 쿼리문의 집합으로 어떠한 동작을 일괄 처리하기 위한 용도로 사용한다.

  - 쿼리 모듈화 – 필요할 때마다 호출만 하면 훨씬 편리하게 MySQL 운영

    (일종의 JAVA 함수 생각하면 됨. 블록 형태로 모듈화 되어 있는 것) , CALL 프로시저_이름( ) 한 줄로 해결되는 편리함

  - 파라미터에 IN, OUT 등을 사용 가능

  - 별도의 반환하는 구문이 없음 – 꼭 필요하다면 여러 개의 OUT파라미터 사용해서 값 반환 가능

  - CALL로 호출

  - 안에 SELECT문 사용 가능

  - delimiter ; delimiter 끝낼 때 한칸 띄고 세미콜론 !!!

  - 매개변수가 필요하면 ( in... out...) 필요없는 경우 그냥 괄호만 ( ) -> create procedure all_del ( )

스토어드 프로시저(Stored Procedure) 의 기본 형식

 

[ 프로시저 쿼리문 예 ] 

학번이 같을 때 학년이 변경되는 프로시저 쿼리문

-- 저장 프로시저 (Stored Procedure : SP) 
-- 이 프로시저를 실행하면 학번 같을 때 학년이 변경되는 프로시저
delimiter //
create procedure test1(in v_stu_no int,
					   in v_stu_grade char(1))			
begin -- begin절 안에 쿼리문 적어야 함
	update student
	set stu_grade=v_stu_grade
    where stu_no=v_stu_no;
end //
delimiter ;

call test1(20153075,3); -- 프로시저 호출(20153075학번이 3학년으로 변경 됨)
select * from student where stu_no=20153075;  -- 1학년 옥한빛

 

 

입력된 사원번호가 같을때 부서번호 변경해라

-- 부서번호를 변경하는 프로시저를 작성해라. (emp 테이블에서) - update~set~where
-- (입력된 사원번호가 같을때 부서번호 변경해라)
delimiter //
create procedure test6(in v_empno int,
					   in v_deptno int)
begin 
	update emp
    set deptno = v_deptno
    where empno = v_empno;
end //
delimiter ;

call test6(7839, 20);

select * from emp where empno = 7839;

 

 

학번을 입력하여 이름을 출력하는 프로시저 => 변수에 대입

-- 저장 프로시저 (Stored Procedure : SP) 
-- 학번을 입력하여 이름을 출력하는 프로시저 => 변수에 대입
-- 20153075와 동일한 학번의 이름을 찾아서 v_stu_name에 저장
delimiter //
create procedure test2(in v_stu_no int,
					   out v_stu_name varchar(12))
begin 
	select stu_name
	into v_stu_name
    from student
    where stu_no=v_stu_no;
end //
delimiter ;
call test2(20153075, @d_stu_name); -- @ 변수 이름 설정, v_stu_name의 값을 @d_stu_name변수에저장
select @d_stu_name;

 

 

학생의 점수를 임의 점수 만큼 올리고(학번, 과목번호가 일치할때만) 그 결과를 출력하는 프로시저

-- 저장 프로시저 (Stored Procedure : SP) 
-- 학생의 점수를 임의 점수 만큼 올리고(학번, 과목번호가 일치할때만) 그 결과를 출력하는 프로시저
delimiter //
create procedure test3(in v_sub_no char(3),
					   in v_stu_no char(9),
					   inout v_enr_grade int)
begin -- 성적 증가 시킴(학번 과목 같으면) 
	update enrol 
    set enr_grade = enr_grade + v_enr_grade
    where stu_no = v_stu_no and sub_no = v_sub_no;
	
    select enr_grade -- 학번 과목 같으면 성적 증가시킨 성적을 v_enr_grade 저장
    into v_enr_grade
    from enrol 
    where stu_no = v_stu_no and sub_no = v_sub_no;
end //
delimiter ;

set @d_enr_grade = 10; -- 성적 10씩 증가시킴

call test3(102, 20153075, @d_enr_grade); -- 102과목을 듣고있는 20153075학생만 성적10 증가시킴

select @d_enr_grade;

 

 

사원번호, 사원이름, 사원직무, 상급자사원번호, 급여, 부서번호를 입력받아 사원 테이블에 삽입하는 프로시저를 작성해라

-- 저장 프로시저 (Stored Procedure : SP) 
-- 신입사원을 채용하였다. 사원번호, 사원이름, 사원직무, 상급자사원번호, 급여, 부서번호를 입력받아
-- 사원 테이블에 삽입하는 프로시저를 작성해라.11
delimiter //
create procedure test4
(in v_empno int,
in v_ename varchar(10),
in v_job varchar(9),
in v_mgr int,
in v_sal decimal(7,2),
in v_deptno int)
begin
   insert into emp(empno,ename,job,mgr,sal,deptno)
    values(v_empno,v_ename,v_job,v_mgr,v_sal,v_deptno);
end //
delimiter ;

call test4(7882,'히히히','대리',7902,7000,20);

select *from emp;

 

 

emp2 테이블에 있는 사원번호와 입력한 사원번호가 같은 사원이름과, 월급, 직무를 검색하는 프로시저 (search_pro) declare

-- emp2 테이블에 있는 사원번호와 입력한 사원번호가 같은 사원이름과, 월급, 직무를 검색하는 프로시저 (search_pro)
delimiter //
create procedure search_pro (in v_empno int)
begin 
	declare v_ename varchar(10); -- 변수 선언 변수 유형을 varchar로 선택
    declare v_sal decimal(7,2);
    declare v_job varchar(9);
    
    select ename, sal, job 
    into v_ename, v_sal, v_job
    from emp
    where empno = v_empno;
    
    select v_ename, v_sal, v_job;
end //
delimiter ;

call search_pro(7369); -- (사원번호)

select * from emp;

 

 

 

emp2 테이블의 모든 데이터를 삭제시키는 프로시저 작성(all_del)

-- emp테이블 복사해서 emp2 테이블 생성
create table emp2 as select * from emp;
select * from emp2;

-- emp2 테이블의 모든 데이터를 삭제시키는 프로시저 작성(all_del)
delimiter //
create procedure all_del ( )
begin 
	delete from emp2;
end //
delimiter ;

call all_del( ); -- 다 지우는 함수 불러오는 작업
	
select * from emp2; -- 다 지워졌는지 확인 출력

 

 

-- v_emame을 선언해서 이름에 'M'이 들어가는 사원들을 다 삭제하는 프로시저 (del_name)

-- 삭제한 데이터를 다시 값 삽입
insert into emp2 select * from  emp;
select * from emp2;

-- v_emame을 선언해서 이름에 'M'이 들어가는 사원들을 다 삭제하는 프로시저 (del_name)
delimiter //
create procedure del_name ( )
begin 
	delete from emp2 where ename like '%M%';
end //
delimiter ;

call del_name();

select * from emp2;

 

 

select into 절

delimiter //
create procedure pr5(in v_stu_no char(9))
begin 
	declare v_stu_name varchar(12);
    select stu_name into v_stu_name
    from student 
    where v_stu_no=stu_no;
    
    select v_stu_name from student;
end //
delimiter ;

select * from student;

call pr5(20131001);

 

 

[ drop procedure test2; ] => 프로시저 삭제 


[ 스토어드 함수 (Stored Function) ]

     set global log_bin_trust_function_creators=1; => 스토어드 함수 생성권한 사용

      파라미터에 IN, OUT 등을 사용할 수 없음 – 모두 입력 파라미터로 사용

     → RETURNS문으로 반환한 값의 데이터 형식 지정 – 본문 안에서는 RETURN문으로 하나의 값 반환

set global log_bin_trust_function_creators=1;
-- 스토어드 함수 생성권한 사용

delimiter //
create function test5(v_enr_grade int) -- 입력값이 있어서 (v_enr_grade int) 적음
      returns char
begin
   declare enr_score char; -- 변수 선언
    if v_enr_grade >=90 then set enr_score:='A';  -- := 대입연산자
    elseif v_enr_grade >=80 then set enr_score:='B';
    elseif v_enr_grade >=70 then set enr_score:='C';
    elseif v_enr_grade >=60 then set enr_score:='D';
    else set enr_score:='F';
    end if;
    return enr_score;
end //
delimiter ;

select test5(95);  -- 파라미터 입력
-- 스토어드 함수 생성권한 사용
set global log_bin_trust_function_creators=1;

-- 스토어드 함수
-- 급여가 제일 높은 사원 이름을 출력하는 함수
delimiter //
create function test6() -- 입력값이 없으면 () 비워둠 
	returns varchar(50) -- 반환유형을 varchar로 받기 
begin
	declare v_ename varchar(50); -- 변수유형을 varchar로 선택
    select ename into v_ename
    from emp
    where sal = (select max(sal) from emp);
    return v_ename;
end //
delimiter ;

select distinct test6() from emp; -- 행이 여러개 출력 되기 때문에 distinct로 중복 제거
select * from emp;

[ 트리거 trigger ]

※ 트리거의 개요 : 사전적 의미로 ‘방아쇠’ - 방아쇠 당기면 ‘자동’으로 총알이 나가듯 실행된다. 테이블에 DML문(Insert, Update, Delete 등) 이벤트가 발생될 때 작동한다. 테이블에 부착되는 프로그램 코드이다. 직접 실행 불가 - 테이블에 이벤트 일어나야 자동 실행된다. IN, OUT 매개 변수를 사용할 수 없다. MySQL은 View에 트리거 부착 불가 ! ! !

 

  ※ 트리거의 종류

      - AFTER 트리거 : 테이블에 INSERT, UPDATE, DELETE 등의 작업이 일어났을 때 작동한다. 이름이 뜻하는 것처럼 해당 작업 후에 (After) 작동한다.

       - BEFORE 트리거 : BEFORE 트리거는 이벤트가 발생하기 전에 작동한다. INSERT, UPDATE, DELETE 세 가지 이벤트로 작동한다.

DELIMITER //
CREATE TRIGGER trigger_name
{ BEFORE | AFTER }  { INSERT | UPDATE | DELETE }
ON table_name
FOR EACH ROW
BEGIN
   -- 트리거 내용
END //
DELIMITER ;

트리거의 사용

※ 트리거가 생성하는 임시 테이블 : INSERT, UPDATE, DELETE 작업이 수행되면 임시 사용 시스템 테이블 이름은 ‘NEW’와 ‘OLD’

-- 삭제한 이후의 값 넣는거는 old 즉, 예전의 

트리거가 생성하는 임시 테이블

create table tmp_tbl( -- 테이블 만들고 

userid varchar(10),
workdate date,
bigo char(1));
desc tmp_tbl; -- 구조 확인하고 

delimiter //
create trigger tri1 -- trigger 만들기 
after update 
on student -- student 테이블을 update 한 이후에 
for each row
begin
	insert into tmp_tbl values('aa',curdate(),'U');
end //
delimiter ;

update student set stu_weight = stu_weight-10;

select distinct * from tmp_tbl;

 /////// userid aa workdate 2024-03-19 bigo U 입력된 테이블 출력 ///////
delimiter //
create trigger tri5
after update
on student  -- student 테이블에서 업데이트 일어난 후 
for each row
begin
	if (old.stu_weight > 40.00) then
        insert into tmp_tbl values('aabb', curdate(), 'A');
        end if;
end //
delimiter ;

update student set stu_name='김길동'
where stu_name='옥한빛';

commit;

select * from tmp_tbl; -- 'aabb', curdate(), 'A' 추가된 것 확인
select * from student; -- 옥한빛이 김길동으로 이름 바뀐 것 확인

 

 

사원테이블에 사원이 추가될 때 5000보다 급여가 많으면  emp500 테이블에 입력된 사원번호, 사원이름, 입력된날짜를 추가 입력하는 트리거 작성

-- 사원테이블에 사원이 추가될 때 5000보다 급여가 많으면 
-- emp500 테이블에 입력된 사원번호, 사원이름, 입력된날짜를 추가 입력하는 트리거 작성
create table emp500(
empno int(4),
ename varchar(10),
workdate date);

delimiter //
create trigger tri6  -- 트리거가 생성하는 임시테이블
after insert
on emp
for each row
begin
	if new.sal > 5000 then 
    insert into emp500 values(new.empno, new.ename, now()); -- 트리거 임시테이블의 new old
    end if;
end //
delimiter ;

insert into emp values(1111, 'gildong','student', 7839, now(), 5600, null, 10);

insert into emp values(2222, 'jack','student', 7839, now(), 4600, null, 10);

select * from emp500; -- jack은 sal이 4600이라 추가 되지 않음 

//// empno 1111 ename gildong workdate 2021-03-19 테이블 출력 됨 ////

 

 

부서테이블(dept)의 데이터 삭제 시 dept_del 테이블에 삭제된 데이터를 저장하는 트리거를 작성

-- 부서테이블(dept)의 데이터 삭제 시 dept_del 테이블에 
-- 삭제된 데이터를 저장하는 트리거를 작성

create table dept_del(
userid varchar(10),
workdate date,
deptno int(2),
dname varchar(14),
loc varchar(13));

delimiter //
create trigger del_tri
after delete 
on dept
for each row
begin
   insert into dept_del  
    values('user',now(),old.deptno,old.dname,old.loc);  -- 삭제한 이후의 값 넣는거라서 old 예전의값
end //
delimiter ;

delete from dept where deptno=40;

select *from dept_del;

select *from dept;

 

 

 

상품 삭제 시 product테이블에서 product_del 테이블에 삽입이 이루어지는 트리거를 작성. p_code , p_name , p_cost , p_group은 기존 product테이블에 있는 값으로 삽입

create table product_del
(u_id varchar(10),
wdate date,
p_code int(6),
p_name varchar(30),
p_cost int,
p_group varchar(30));

-- 트리거는 이벤트 처리 작업 // 프로시저는 프로그램 모듈화 호출할 때 마다 쓸 수 있다

-- 상품 삭제 시(product테이블에서) product_del 테이블에 삽입이 이루어지는트리거를 작성해라.
-- p_code , p_name , p_cost , p_group은 기존 product테이블에 있는 값으로 삽입해라.
delimiter //
create trigger product_del
after delete
on product
for each row
begin 
	insert into product_del(p_code, p_name, p_cost, p_group) 
    values(old.p_code, old.p_name, old.p_cost, old.p_group);
end //
delimiter ;

delete from product where p_code='201';

select * from product_del;

 

 

 

[ 커서 Cursor  ] ( 별로 사용 하지 않음 )

  - 스토어드 프로시저 내부에 사용

  - 일반 프로그래밍 언어의 파일 처리와 방법이 비슷함 – 행의 집합을 다루기에 편리한 많은 기능을 제공

  - 테이블에서 여러 개의 행을 쿼리한 후, 쿼리의 결과인 행 집합을 한 행씩 처리하기 위한 방식

-- 커서
delimiter //
create procedure test10()
begin 
	declare v_stu_no char(9);
    declare v_sub_no char(3);
    declare v_enr_grade int;
    declare done int default 0;

	declare endOfRow boolean default false; -- 행의 끝 여부
    
    declare c1 cursor for select stu_no, sub_no, enr_grade 
    from enrol where sub_no=104; -- 커서 선언 !! 104번에 해당하는 stu_no, sub_no, enr_grade 뽑아내겠다 
		
    declare continue handler for not found set done=1; -- 반복 조건 선언 !!
    -- 더 이상 읽을 행이 없으면 done 값을 1로 세팅
    
    open c1; -- 커서 열기 !! 커서 열고 커서 이름 넣어주기 
    
    li:loop -- 반복문 이름 li로 지정
	fetch from c1 into v_stu_no, v_sub_no, v_enr_grade; -- 커서에서 데이터 가져오기 !!
	if done then leave li;                              -- fetch from select into 랑 같은 개념
        end if;
        select v_stu_no,  v_sub_no, v_enr_grade;
        end loop;
        close c1; -- 커서 닫기 !!
end //
delimiter ;

call test10; -- result 결과 2개 나옴

select * from enrol;

drop procedure test10;

[ MySQL 이론 ]

[ 스토어드 프로시저(Stored Procedure) ] ☆★☆★

  - 저장 프로시저라고도 불린다. MySQL에서 제공되는 프로그래밍 기능이다.

  - 쿼리문의 집합으로 어떠한 동작을 일괄 처리하기 위한 용도로 사용한다.

  - 쿼리 모듈화 – 필요할 때마다 호출만 하면 훨씬 편리하게 MySQL 운영

    (일종의 JAVA 함수 생각하면 됨. 블록 형태로 모듈화 되어 있는 것) , CALL 프로시저_이름( ) 한 줄로 해결되는 편리함

스토어드 프로시저(Stored Procedure) 의 기본 형식

 

※ 스토어드 프로시저의 개요 :

 - 스토어드 프로시저의 수정과 삭제

     → 수정 : ALTER PROCEDURE

     → 삭제 : DROP PROCEDURE

 

 - 매개 변수의 사용 (입력 매개 변수를 지정하는 형식)

     → IN 입력_매개 변수_이름 데이터_형식 •입력 매개 변수가 있는 스토어드 프로시저 실행 방법

     → CALL 프로시저_이름(전달 값); •출력 매개 변수 지정 방법

     → OUT 출력_매개 변수_이름 데이터_형식 – 출력 매개 변수에 값 대입하기 위해 주로 SELECT… INTO문 사용

 

- 프로그래밍 기능

 

- 더 강력하고 유연한 기능 포함하는 스토어드 프로시저 생성

 

- 스토어드 프로시저 내의 오류 처리 : 스토어드 프로시저 내부에서 오류가 발생했을 경우 

       DECLARE 액션 HANDLER FOR 오류조건 처리할_문장 구문

 

※ 스토어드 프로시저의 특징

  - MySQL의 성능 향상 : 긴 쿼리가 아니라 짧은 프로시저 내용만 클라이언트에서 서버로 전송 – 네트워크 부하 줄임

 

  - 유지관리가 간편 : 응용 프로그램에서는 프로시저만 호출 – 데이터베이스 단에서 관련된 스토어드 프로시저의 내용 일관되게 수정/유지보수

 

  - 모듈식 프로그래밍 가능 : 언제든지 실행 가능 + 편리한 관리 •모듈식 프로그래밍 언어와 동일핚 장점

 

  - 보안 강화에 편리 : 스토어드 프로시저에만 접근 권핚을 주어 DB가 안전해짐

 

 

[ 스토어드 함수 (Stored Function) ]

   - 사용자가 직접 만들어서 사용하는 함수

   - 스토어드 프로시저와 상당히 유사 : 형태와 사용 용도에 있어 차이 있음 스토어드 함수의 개요

 

※ 스토어드 함수 와 스토어드 프로시저의 차이점

 스토어드 함수 : 

     set global log_bin_trust_function_creators=1; => 스토어드 함수 생성권한 사용

      파라미터에 IN, OUT 등을 사용할 수 없음 – 모두 입력 파라미터로 사용

     → RETURNS문으로 반환한 값의 데이터 형식 지정 – 본문 안에서는 RETURN문으로 하나의 값 반환

      SELECT 문장 안에서 호출

      안에서 집합 결과 반환하는 SELECT 사용 불가 – SELECT… INTO… 는 집합 결과 반환하는 것이

                                                                                       아니므로 예외적 으로 스토어드 함수에서 사용 가능

      어떤 계산 통해서 하나의 값 반홖하는데 주로 사용

 

 스토어드 프로시저 : ( 스토어드 함수보단 스토어드 프로시저를 더 많이 사용 ☆ )

     → 파라미터에 IN, OUT 등을 사용 가능

     → 별도의 반환하는 구문이 없음 – 꼭 필요하다면 여러 개의 OUT파라미터 사용해서 값 반환 가능

     → CALL로 호출

     → 안에 SELECT문 사용 가능

     → 여러 SQL문이나 숫자 계산 등의 다양한 용도로 사용

 

 

[ 커서 Cursor  ]

  - 스토어드 프로시저 내부에 사용

  - 일반 프로그래밍 언어의 파일 처리와 방법이 비슷함 – 행의 집합을 다루기에 편리한 많은 기능을 제공

  - 테이블에서 여러 개의 행을 쿼리한 후, 쿼리의 결과인 행 집합을 한 행씩 처리하기 위한 방식

커서의 처리 순서

 

 

[ 트리거(Trigger) ] ☆★☆★

  ※ 트리거의 개요 : 사전적 의미로 ‘방아쇠’ - 방아쇠 당기면 ‘자동’으로 총알이 나가듯 실행된다. 테이블에 DML문(Insert, Update, Delete 등) 이벤트가 발생될 때 작동한다. 테이블에 부착되는 프로그램 코드이다. 직접 실행 불가 - 테이블에 이벤트 일어나야 자동 실행된다. IN, OUT 매개 변수를 사용할 수 없다. MySQL은 View에 트리거 부착 불가 ! ! !

 

  ※ 트리거의 종류

      - AFTER 트리거 : 테이블에 INSERT, UPDATE, DELETE 등의 작업이 일어났을 때 작동한다. 이름이 뜻하는 것처럼 해당 작업 후에 (After) 작동한다.

       - BEFORE 트리거 : BEFORE 트리거는 이벤트가 발생하기 전에 작동한다. INSERT, UPDATE, DELETE 세 가지 이벤트로 작동한다.

트리거의 사용

※ 트리거가 생성하는 임시 테이블 : INSERT, UPDATE, DELETE 작업이 수행되면 임시 사용 시스템 테이블 이름은 ‘NEW’와 ‘OLD’

트리거가 생성하는 임시 테이블

 

※ BEFORE 트리거의 사용 : 테이블에 변경이 가해지기 전에 작동한다.

    BEFORE 트리거의 좋은 활용 예 – BEFORE INSERT 트리거를 부착해 놓으면 입력될 데이터 값을 미리 확인해서 문제가 있을 경우에 다른 값으로 변경

   생성된 트리거 확인 – SHOW TRIGGERS FROM sqlDB;

   트리거를 삭제하자. – DROP TRIGGER userTbl_BeforeInsertTrg;

 

※다중 트리거 (Multiple Triggers) : 하나의 테이블에 동일한 트리거가 여러 개 부착되어 있는 것

    Ex) AFTER INSERT 트리거가 한 개 테이블에 2개 이상 부착

※ 중첩 트리거 (Nested Triggers) : 트리거가 또 다른 트리거를 작동시키는 것. 시스템 성능 저하의 원인이 되기도 함.

중첩 트리거 (Nested Triggers)

※ 트리거의 작동 순서 : 하나의 테이블에 여러 개의 트리거가 부착된 경우

    트리거의 작동 순서 지정 가능 – { FOLLOWS | PRECEDES } other_trigger_name 에서 설정

    중첩 트리거 작동 학습 – 테이블 내용을 전체 살펴보는 것으로 결과 확인

 


[ MySQL 복습 ]

 

[ 문제풀이 1 -  book, orders, customer 테이블 생성 ]

-- 논리적 모델링 테이블 생성으로 후에 물리적 모델링 진행
create table book(
bookid int primary key,
bookname varchar(100),
publisher varchar(100),
price int);

create table orders(
orderid int primary key,
custid int,
bookid int,
saleprice int,
orderdate date);

create table customer(
custid int primary key,
name varchar(10),
address varchar(100),
phone varchar(20));

alter table orders -- book 테이블을 수정하겠다
add 
constraint fk_ord foreign key(bookid) 
references book(bookid);

INSERT INTO BOOK VALUES (1, '컴퓨터의 역사', '아이티', 7000);
INSERT INTO BOOK VALUES (2, '컴퓨터는 무엇일까', '굿북', 13000);
INSERT INTO BOOK VALUES (3, '컴퓨터의 이해', '비트아이티', 22000);
INSERT INTO BOOK VALUES (4, '자바 이론', '비트아이티', 35000);
INSERT INTO BOOK VALUES (5, '데이터베이스 교본', '아이티', 8000);
INSERT INTO BOOK VALUES (6, 'HTML 기술', '아이티', 6000);
INSERT INTO BOOK VALUES (7, '스프링의 개념', '에비씨미디어', 20000);
INSERT INTO BOOK VALUES (8, '스프링을 부탁해', '에비씨빛미디어', 13000);
INSERT INTO BOOK VALUES (9, '파이썬 이야기', '코딩빔', 7500);
INSERT INTO BOOK VALUES (10, 'python story', 'Pearson', 13000);

INSERT INTO CUSTOMER VALUES (1, '박건우', '인천시 송도', '010-1111-2222');
INSERT INTO CUSTOMER VALUES (2, '김선해', '서울시 종로구', '010-2111-2222');   
INSERT INTO CUSTOMER VALUES (3, '장지혜', '서울시 용산구', '010-3111-2222');   
INSERT INTO CUSTOMER VALUES (4, '추오섭', '경기도 의정부', '010-4111-2222');   
INSERT INTO CUSTOMER VALUES (5, '박승철', '서울시 마포구', NULL);

INSERT INTO ORDERS VALUES (1, 1, 1, 6000, '2022-05-01');
INSERT INTO ORDERS VALUES (2, 1, 3, 21000, '2022-05-03');
INSERT INTO ORDERS VALUES (3, 2, 5, 8000, '2022-05-03');
INSERT INTO ORDERS VALUES (4, 3, 6, 6000, '2022-05-04');
INSERT INTO ORDERS VALUES (5, 4, 7, 20000, '2022-05-05');
INSERT INTO ORDERS VALUES (6, 1, 2, 12000, '2022-05-07');
INSERT INTO ORDERS VALUES (7, 4, 8, 13000, '2022-05-07');
INSERT INTO ORDERS VALUES (8, 3, 10, 12000, '2022-05-08');
INSERT INTO ORDERS VALUES (9, 2, 10, 7000, '2022-05-09');
INSERT INTO ORDERS VALUES (10, 3, 8, 13000, '2022-05-10');

/// 테이블 생성후 값 입력 후 잘 들어 갔는지 확인 ///
select * from book;
select * from orders;
select * from customer;

 

 

-- 1.   김선해 고객의 전화번호를 찾아라.
select phone from customer where name='김선해';

-- 2.   모든 도서의 이름과 가격을 검색해라.
select bookname, price from book;

-- 3.   모든 도서의 도서번호, 도서이름, 출판사, 가격을 검색해라.
select * from book;

-- 4.   도서 테이블에 있는 모든 출판사를 검색해라. (중복제거해서)
select distinct publisher from book;

-- 5.   가격이 20000원 미만인 도서를 검색해라.
select * from book where price < 20000;

-- 6.   가격이 10000원 이상 20000 이하인 도서를 검색해라.
select * from book where price between 10000 and 20000;

-- 7.   출판사가 ‘아이티’ 혹은 ‘비트아이티’ 인 도서를 검색해라.
select * from book where publisher='아이티' or publisher='비트아이티';
select * from book where publisher in('아이티','비트아이티');


-- 8.   출판사가 ‘아이티’ 혹은 ‘비트아이티’ 아닌 도서를 검색해라.
select * from book where not publisher='아이티' and not publisher='비트아이티';
select * from book where publisher not in('아이티','비트아이티');

-- 9.   ‘컴퓨터의 역사’를 출간한 출판사를 검색해라.
select publisher from book where bookname='컴퓨터의 역사';

-- 10.   도서이름에 ‘컴퓨터’가 포함된 출판사를 검색해라.
select publisher from book where bookname like '%컴퓨터%';

-- 11.   도서이름의 왼쪽 두번 째에 ‘퓨’라는 문자열을 갖는 도서를 검색해라.
select * from book where bookname like '_퓨%';

-- 12.   컴퓨터에 관한 도서 중 가격이 20000원 이상인 도서를 검색해라.
select * from book where price >= 20000;

-- 13.   도서를 이름순으로 검색해라.
select * from book order by bookname;

-- 14. 도서를 가격순으로 검색하고, 가격이 같으면 이름순으로 검색해라.
select * from book ORDER BY price, bookname;

-- 15. 도서를 가격의 내림차순으로 검색해라. 가격이 같다면 출판사의 오름차순으로 검색해라.
select * from book ORDER BY price desc, publisher;

-- 16. 고객이 주문한 도서의 총 판매액을 구해라.
select sum(saleprice) as sum_price from orders;

-- 17. 2번 김선해 고객이 주문한 도서의 총 판매액을 구해라.
select sum(saleprice) as sum_price from orders where custid = 2; -- 만약 김선해로 찾을 시 JOIN 필요

-- 18. 고객이 주문한 도서의 총 판매액, 평균값, 최저가, 최고가를 구해라.
select sum(saleprice) as sum_price, avg(saleprice) as avg_price, 
min(saleprice) as min_price, max(saleprice) as max_price from orders;

-- 19. 23서점의 도서 판매 건수를 구해라. 
select count(*) as all_sale_count from orders;

-- 20. 고객별로 주문한 도서의 총 수량과 총 판매액을 구해라.
select custid, count(*), sum(saleprice) from orders group by custid;

-- 21. 가격이 8000원 이상인 도서를 구매한 고객에 대하여 고객별 주문 도서의 총 수량을 구해라. 단, 두 권 이상 구매한 고객만 구해라.
select custid, count(*) from orders where saleprice >= 8000
group by custid having count(custid)>=2;

select custid, count(*) as BUY 
from (select ord.custid, ord.bookid, ord.saleprice, bk.bookname, bk.price, cust.name
	  from orders ord, book bk, customer cust
      where ord.bookid = bk.bookid 
      and  ord.custid = cust.custid
      and bk.price >= 8000 ) AA -- AA는 별칭 안 주면 Error Code 1248 뜸.
	  group by custid having count(custid)>=2;  -- 테이블 3개를 조인시켜서 다 연결해줌. 위와 달리 custid 2도 출력됨

-- 22. 고객과 고객의 주문에 관한 데이터를 모두 보여라.
select * from customer cust
JOIN orders ord
ON cust.custid=ord.custid;

-- 23. 고객과 고객의 주문에 관한 데이터를 고객번호 순으로 정렬하여 보여라.
select * from customer cust
JOIN orders ord
ON cust.custid=ord.custid
ORDER BY cust.custid;

-- 24. 고객의 이름과 고객이 주문한 도서의 판매가격을 검색해라.
select name, saleprice 
from customer cust
JOIN orders ord ON cust.custid = ord.custid;

-- 25. 고객별로 주문한 모든 도서의 총 판매액을 구하고, 고객별로 정렬해라.
select custid, sum(saleprice) from orders group by custid order by custid;

-- 26. 고객의 이름과 고객이 주문한 도서의 이름을 구해라.
select name, bookname 
from customer cust
JOIN orders ord 
ON cust.custid = ord.custid
JOIN book bk
ON ord.bookid = bk.bookid;

-- 27. 가격이 20000원인 도서를 주문한 고객의 이름과 도서의 이름을 구해라.
select name, bookname
from customer cust
JOIN orders ord 
ON cust.custid = ord.custid
JOIN book bk
ON ord.bookid = bk.bookid
where saleprice = 20000;

-- 28. 도서를 구매하지 않은 고객을 포함하여 고객의 이름과 고객이 주문한 도서의 판매가격을 구해라. outer join 활용
select name, bookname, price 
from customer cust
LEFT JOIN orders ord 
ON cust.custid = ord.custid
LEFT JOIN book bk
ON ord.bookid = bk.bookid;

-- 29. 가장 비싼 도서의 이름을 구해라.
select bookname from book ORDER BY price DESC LIMIT 1;

-- 30. 도서를 구매한 적이 있는 고객의 이름을 검색해라.
SELECT DISTINCT customer.name
FROM orders
JOIN customer ON customer.custid = orders.custid;

-- 31. 비트아이티에서 출판한 도서를 구매한 고객의 이름을 보여라.
select name
from orders join book using(bookid) join customer using(custid)
where publisher='비트아이티';

-- 32. 출판사별로 출판사의 평균 도서 가격보다 비싼 도서를 구해라.
select bk.bookname, bk.price, bk_avg.publisher, bk_avg.avg_price
from book bk,
(select publisher, avg(price) as avg_price
from book
group by publisher) bk_avg
where bk.publisher= bk_avg.publisher
and bk.price > bk_avg.avg_price;

-- 33. Book테이블에 새로운 도서 ‘공학 도서’를 삽입해라.
-- 공학 도서는 더샘에서 출간했으며 가격을 40000원이다.
insert into book values(11,'공학 도서','더샘',40000);

-- 34. Book테이블에 새로운 도서 ‘공학 도서’를 삽입해라.
-- 공학 도서는 더샘에서 출간했으며 가격은 미정이다.
insert into book values(12,'공학 도서','더샘',null);

-- 35. Customer테이블에서 고객번호가 5인 고객의 주소를
-- ‘서울시 서초구’로 변경해라.
update customer
set address='서울시 서초구'
where custid=5;

-- 36. Customer테이블에서 박승철 고객의 주소를 김선해 고객의 주소로 변경해라.
update customer
set address=(select address from (select address customer 
                                 where name='김선해') as A)
                                 where name='박승철';

-- 37. 아이티에서 출판한 도서의 제목과 제목의 글자수를 확인해라.
select bookname, char_length(bookname)
from book
where publisher='아이티';

-- 38. 23서점의 고객 중에서 같은 성(이름 성)을 가진 사람이
-- 몇 명이나 되는지 성별 인원수를 구해라.
select sung,count(*)
from (select substr(name,1,1) as sung
from customer) A
group by sung;

-- 39. 23서점은 주문일로부터 10일 후 매출을 확정한다.
-- 각 주문의 확정일자를 구해라.
select orderdate, (orderdate+10) as confirmdate
from orders;

-- 40. 23서점이 2022년 5월 7일에 주문받은 도서의
-- 주문번호, 주문일, 고객번호, 도서번호를 모두 보여라.
-- 주문일은 ‘yyyy-mm-dd요일’형태로 표시한다.
select orderid, date_format(orderdate,'%y-%m-%d-%w요일'), custid, bookid
from orders
where orderdate='2022-05-07';

-- 41. 이름, 전화번호가 포함된 고객목록을 보여라.
-- 단, 전화번호가 없는 고객은 ‘연락처없음’으로 표시해라.
select name, ifnull(phone,'연락처없음')
from customer;

-- 42. 평균 주문금액 이하의 주문에 대해 주문번호와 금액을 보여라.
select orderid, saleprice
from orders
where saleprice <= (select avg(saleprice) from orders);

-- 43. 각 고객의 평균 주문금액보다 큰 금액의 주문 내역에 대해
-- 주문번호, 고객번호, 금액을 보여라.
select orderid, custid, saleprice
from orders
where saleprice > all(select avg(saleprice) from orders
group by custid);

SELECT o.orderid, o.custid, o.saleprice
FROM orders o
WHERE o.saleprice > (SELECT AVG(saleprice) FROM orders WHERE custid = o.custid);
-- 내가 조회하는 orders테이블의 고객아이디랑 AVG를해서 구해온데이터의 고객아이디랑 같은애들끼리의 평균치를 구하는 것 !!!
-- 각각의 고객의 자기자신의 평균금액보다 큰데이터가 필요해

-- 44. 서울시에 거주하는 고객에게 판매한 도서의 총판매액을 구해라.
select sum(saleprice)
from orders
where custid in (select custid from customer
where address like '서울%');
-----------------------------------------------------
select sum(saleprice)
from orders ord, customer cust
where ord.custid=cust.custid and address like '서울%';

-- 45. Customer테이블에서 고객번호가 5인 고객을 삭제해라.
delete from customer where custid=5;

 

 

[ 문제풀이 2 - product , trade, customer, stock 테이블 생성 ]

create table product(
p_code char(3) not null,
p_name varchar(30),
p_cost int,
p_group varchar(30),
constraint product_pk primary key(p_code));

insert into product values('101','19인치 모니터',150000,'모니터');
insert into product values('102','22인치 모니터',200000,'모니터');
insert into product values('103','25인치',260000,'모니터');
insert into product values('201','유선마우스',7000,'마우스');
insert into product values('202','무선마우스',18000,'마우스');
insert into product values('301','유선키보드',8000,'키보드');
insert into product values('302','무선키보드',22000,'키보드');
insert into product values('401','2채널 스피커',10000,'스피커');
insert into product values('402','5.1채널 스피커',120000,'스피커');

create table trade(
t_seq int not null,
p_code char(3),
c_code varchar(4),
t_date date,
t_qty int,
t_cost int,
t_tax int,
constraint trade_pk primary key(t_seq));

insert into trade
values (61,'131','101','2016-04-01',10,150000,150000);
insert into trade
values (5,'102','102','2016-04-26',8,200000,160000);
insert into trade
values (8,'103','101','2016-05-20',2,260000,52000);
insert into trade
values (3,'201','103','2016-04-13',7,7000,4900);
insert into trade
values (2,'201','101','2016-04-12',5,7000,3500);
insert into trade
values (9,'202','104','2016-06-02',8,18000,14400);
insert into trade
values (6,'301','103','2016-05-02',12,8000,9600);
insert into trade
values (10,'302','103','2016-06-09',9,22000,19800);
insert into trade
values (4,'401','104','2016-04-20',15,10000,15000);

create table customer(
c_code varchar(4) not null,
c_name varchar(30),
c_ceo varchar(12),
c_addr varchar(100),
c_phone varchar(13),
constraint custromer_pk primary key(c_code));

insert into customer values('101','늘푸른회사','김수종','경기도 안산시','010-1234-5678');
insert into customer values('102','사랑과바다','박나리','경기도 평택시','010-1122-3344');
insert into customer values('103','대한회사','이민수','서울시 구로구','010-3785-8809');
insert into customer values('104','하얀기판','허진수','경상북도 포항시','010-8569-3468');
insert into customer values('105','한마음한뜻','하민우','인천시 남동구','010-9455-6033');

select * from product;
select * from stock;
select * from trade;
select * from customer;
-- 1. 상품 정보(product)테이블에 열 이름이 ‘비고’ 라는 열을 varchar2(20)으로 삽입해라.
alter table product add 비고 varchar(20);

-- 2. 1번에서 삽입한 열이 상품 정보(product)테이블에 삽입되었는지 확인해라.
select * from product;

-- 3. 상품 정보(product)테이블에 ‘비고’ 열의 구조를 char(3)으로 변경해라.
alter table product modify 비고 char(3);

-- 4. 상품코드 401에 대한 거래내역 뷰(v_trade)를 만들어라.
create view v_trade as select t.* from trade t where t.p_code = '401';

select * from v_trade;

-- 5. 상품 정보(product)테이블에 가장 최근에 들어온 거래처 코드 정보를 검색해라(top-n질의)
SELECT p.p_code, p.p_name, t.c_code, MAX(t.t_date)
FROM product p
JOIN trade t ON p.p_code = t.p_code
GROUP BY p.p_code, p.p_name, t.c_code
ORDER BY MAX(t.t_date) DESC
LIMIT 1;

select c_code from product p 
join trade t 
on p.p_code=t.p_code 
order by t_date desc
limit 1;

-- 6. 상품을 삽입하는 프로시저를 생성해라.call p_pro(‘403’, ’7.1채널 스피커’, 180000, ‘스피커’); 완료되었다.
DELIMITER //
CREATE PROCEDURE p_pro(in v_p_code int,
in v_p_name varchar(30),
in v_p_cost int,
in v_p_group varchar(30))
BEGIN
INSERT INTO product(p_code, p_name, p_cost, p_group)
VALUES(v_p_code, v_p_name, v_p_cost, v_p_group);
END //
DELIMITER ;

CALL p_pro(403, '7.1채널 스피커', 180000, '스피커');
728x90