190603_DAY38 <복습>, <조건문>,<반복문>, ,

<PL/SQL>

  • SQL언어에 절차적인 프로그래밍 언어 요소(조건문,반복문)를 가미해 만든 것

  • 여러개의 SQL문(DQL,DML) 사이에 연결관계를 표현

    select 컬럼명 into 변수명

    from 테이블명

    if 변수명 < 10
    then insert into~ end if;

<PL/SQL구조>

declare -- 선언부

--   실행부에서 사용하는 변수에 대한 선언!!
    a number(4); -- 변수선언
    b emp.ename%type; -- 변수선언( 존재하는 테이블안의 컬럼이 갖는 자료형을 참조 )
    c number(2) := 30;

begin --실행부 시작
    a := 300;

    SQL문1 작성
    SQL문2 작성
    SQL문3( DQL, DML ) 작성--------1번 실행
           ---- 주의 select empno, ename, sal into a, b, c 
               --        from emp;
               dbms_output.put_line(empno); -- X ==> 조회된 컬럼명 empno 인식 불가
               dbms_output.put_line(a); -- O ==> 조회된 사원번호를 begin~end 사이에서 a변수로 사용!

            if(조건식)
                then SQL문4; -- 조건식 참일때 -----0,1번 실행
            end if; (if문 종결문, {} 못씀)

            for()
            {
                SQL문5; -- 0 ~ 무한대 실행
            }
end; -- 실행부 끝
/

<조건문> begin~end사이에 들어갈 수 있는

  1. IF문

    • 형식

      IF 조건식
          THEN --시작
              조건식 결과가 참일 때 실행할 (SQL)문장;
      END IF; -- 끝
  2. IF ~ ELSE문

    • 형식

      IF 조건식
          THEN 조건식 결과가 참일 때 실행할 문장;
          ELSE 조건식 결과가 거짓일 때 실행할 문장;
      END IF;
    • 문제

      문제) 특정사원이 커미션을 받는지 안 받는지 구분해서 출력하시오
          예1 : 사번 7788은 SCOTT사원이고 커미션을 받지 않습니다.
      
          예2 : 사번 7654는 MARTIN사원이고 커미션을 1400 받습니다.
          => IF_ELSE_TEST.SQL
      
      declare 
          vEMPNO emp.empno%type;
          vENAME emp.ename%type;
          vCOMM emp.comm%type;
      
      begin
          select empno, ename, comm into vEMPNO, vENAME, vCOMM -- v는 변수명
          from emp
          where empno = 7654;
      
          IF (vCOMM IS NOT NULL)
                      THEN
                          dbms_output.put_line( vEMPNO ||'은(는) '||vENAME ||'사원이고 커미션을' || vCOMM ||'받습니다.');                    
                      ELSE
                          dbms_output.put_line( '커미션 안받음' );
          END IF;
      end;
      /
      문제) 특정사원 한 명의 사원번호, 사원명, 연봉을 출력하시오.
           (연봉계산은 급여*12+comm)
      
          ==> where empno=7788;   where empno=7654;
          ==> 예) 사번 7788은 SCOTT사원이고 연봉은 36000입니다.
      
      declare 
          vempno emp.empno%type;
          vename emp.ename%type;
          vsal emp.sal%type;
          vcomm emp.comm%type;
      
          annsal number;
      begin
          select empno, ename, sal, comm into vempno, vename, vsal, vcomm
          from emp
          where empno = 7788;
      
      
      
     IF(vcomm is null)
         then
             annsal := vsal * 12 + 0;
         else
             annsal := vsal * 12 + vcomm;
     END IF;
             dbms_output.put_line('사번' || vempno || '은(는) ' || vename || 
                                    '사원이고 ' || '연봉은' || annsal || ' 입니다.' );
 end;
 /
 ```
  1. IF ~ ELSIF ~ ELSE 문

    • 형식

      IF (조건식1)
          THEN 조건식1 참일때 실행할 문장;
          ELSIF (조건식2)
              THEN 조건식1이 거짓이고 조건식2 참일때 실행할 문장
          ELSIF (조건식3)
              THEN 조건식1,2가 거짓이고 조건식3 참일때 실행할 문장
          ELSE 조건식1,2,3 이 거짓일 때 실행할 문장
      END IF;
    • 문제

      문제) 특정사원의 사원번호, 사원명, 소속된 부서명을 출력하시오
      예 : 사번 7788은 SCOTT 사원이고 RESEARCH 부서에 근무합니다.
      if_elsif_test.sql
      
      declare
          vempno emp.empno%type;
          vename emp.ename%type;
          vdeptno emp.deptno%type;
          vdname dept.dname%type;
      
      begin
          vempno := 7788;
      
          select ename, deptno into vename, vdeptno
          from emp
          where empno = vempno; -- 여기서 empno 써서 select에 안써도 됨.
      
          if (vdeptno = 10)
              then vdname := 'ACCOUNTING';
          elsif (vdeptno = 20)
              then vdname := 'RESEARCH';
          elsif (vdeptno = 30)
              then vdname := 'SALES';
          else
              vdname := 'OPERATION';
          end if;    
      
          dbms_output.put_line('사번' || vempno || '은(는) ' ||
                                          vename || '사원이고 ' || vdname || '부서에 근무합니다.');
      
      end;
      /

<반복문>

  1. LOOP (반복문)

    • 형식

      LOOP
          반복실행할 문장1;
          반복실행할 문장2;
          반복실행할 문장3;
          EXIT [WHEN 조건식]; -- 탈출조건
      END LOOP;
    • 문제

      문제) 1부터 10까지 출력하세요
      loop_test.sql
      declare
      
          i number := 0;
      
      begin
          loop
              i := i + 1;
              dbms_output.put_line( i || '번째  안녕~!' );
              exit when i = 10;
          end loop;
      end;
      /
      
      문제2) 화면에 3, 6, 9를 출력하시오
      declare
      
          j number := 0;
      
      begin
          loop
              j := j + 3;
              dbms_output.put_line( j );
              exit when j = 9;
          end loop;
      end;
      /
  2. FOR LOOP

    • 형식

      FOR 변수 IN 최소값.. 최대값
      LOOP
          반복 실행할 문장;
      END LOOP;
    • 문제

      문제) 화면에 '나는 SQL이 좋아요!! '를 10번 출력하시오.
      for_test.sql
      
      declare
      
      begin
          FOR i in 1..10
          LOOP
          dbms_output.put_line('나는 딩꼬가 좋아요!!==> ' || i);
          END LOOP;
      
          dbms_output.put_line('++++++++++++++++++++++++');
          FOR i in 10..1
          LOOP
          dbms_output.put_line('10부터 1까지는 에러는 없지만 출력도 안되네');
          END LOOP;
      
          dbms_output.put_line('++++++++++++++++++++++++');
          FOR i in reverse 1..10
          LOOP
          dbms_output.put_line('in 뒤에 reverse 사용해서 10부터 1까지' || i);
          END LOOP;
      end;
      /
      
      문제) 3단에서 5단까지 출력하시오.
      for_loop 사용 
      for_dan.sql
      
      declare
      
      begin
          FOR dan in 3..5
          LOOP
              dbms_output.put_line('< ' || dan || '단 >');
              FOR i in 1..9
              LOOP
               dbms_output.put_line( dan || ' X ' || i || ' = ' || dan*i);
      
          END LOOP;
          END LOOP;
      
      end;
      /
  3. WHILE LOOP

    • 형식

      WHILE 조건식
      LOOP
          반복실행문장;
      END LOOP;
    • 문제

      문제) 1부터 10까지의 합을 출력하시오
      declare
          i number := 1;
          total number := 0;
      begin
          while i <= 10
          loop
              total := total+i;
              i := i+1;
          end loop;
      
          dbms_output.put_line('total = ' || total);
      end;
      /

<Stored Procedure'> ★저장 프로시저

  • 자주사용되는 DQL, DML 을 모듈화 시켜서 DB에 저장하였다가 필요할 때 호출해서 사용!

  • JAVA의 메소드와 같은 역할

  • 형식)

    CREATE [OR REPLACE] PROCEDURE 프로시저명( 변수명1 [IN|OUT] 자료형, 변수명2 자료형)
    IS
        변수선언;
    BEGIN
        실행할 문장;
        실행할 문장;
        실행할 문장;
        --초기화, SQL문, 함수호출, 절차적요소 ( 조건문, 반복문 )
    END;
    /
  • 실행방법)

    EXECUTE 프로시저명();
  • 문제)

    문제) 부서테이블 (dept3)에서 40번 부서를 삭제하시오 ( 프로시저 사용 )
    - pro_test.sql
    
    drop table dept3;
    
    create table dept3
    as select * from dept;
    ---
    create or replace procedure del_dept
    
    is
        -- 실행부에서 사용 할 변수 선언!
    begin
    
        delete from dept3
        where deptno = 40;
    
        dbms_output.put_line('#40번 부서를 삭제하였습니다.');
    
    end;
    /
    ---
    --하고 끝나는것이 아니라 프로시저를 실행해야 한다
    EXTCUTE del_dept();
    
    --이제 20번 부서 지우고 싶은데
    --그럼 또 재정의하고, 등록하고 삭제해야해?!...
    
    drop table dept3;
    
    create table dept3
    as select * from dept;
    
    --다시 해보자!
    create or replace procedure del_dept(delNo number)
    is
        -- 실행부에서 사용 할 변수 선언!
    begin
        delete from dept3
        where deptno = delNo;
        dbms_output.put_line('#40번 부서를 삭제하였습니다.');
    end;
    /
    --
    --이제 프로시저 등록 후 
    -- 실행할 때, 
    EXECUTE del_dept(원하는 deptno); --하면 
    --원하는 dept3 테이블의 deptno 컬럼이 지워진다.
    --=====================================================================
    
    -- 0603/pro_test.sql (40번 부서 삭제)
    -- 0603/pro_test.sql (특정 부서 삭제)
    
    --create or replace procedure del_dept
    -- 호출?  exec del_dept  또는   exec del_dept()
    --create or replace procedure del_dept(delNo number)
    -- 호출?  exec del_dept(40)
    create or replace procedure del_dept(delNo in number, tomorrow out varchar2)
    -- 변수 선언  variable tom  varchar2(15);
    -- 바인드 변수(전달 변수) 사용==>  :변수명
    -- 호출?  exec del_dept(40, :tom)
    -- 확인   print tom;
    is
      -- 실행부에서 사용할 변수 선언!!
    
    begin
        tomorrow := '토요일';
      /*    
       delete from dept3
       where deptno=40;
       dbms_output.put_line('#40번 부서를 삭제하였습니다!!');    
      */
       delete from dept3
       where deptno=delNo;
       dbms_output.put_line('#'||delNo||
                                 '번 부서를 삭제하였습니다!!');    
       commit;
    
    end;
    /
    
    show errors;
    
    variable tom varchar2(15);
    exec del_dept(40, :tom);
    
    --============================================================
    문제 ) select 문을 통해 tomorrow에 오늘의 요일의 아웃되도록
    
    create or replace procedure del_dept(delNo in number, tomorrow out varchar2)
    
    is
    
    begin
       delete from dept3
       where deptno=delNo;
       dbms_output.put_line('#'||delNo||
                                 '번 부서를 삭제하였습니다!!');    
       commit;
    
    --   select to_char(sysdate, 'yy/mm/dd') into -- 년월일 
       select to_char(sysdate, 'day') into tomorrow -- 년월일 
       from dual;
    end;
    /
    
    show errors;
    

    1559542009180

    문제) 사원테이블 (emp3)에서 특정 사원명을 (매개변수) 입력을 통해 삭제하는 프로시저를 작성하고 현재 사원수를 출력하시오
    
    drop table emp3;
    create table emp3
    as select empno, ename, sal
    from emp;
    
    --> pro_test2.sql
    --> 프로시저 명 : del_ename
    
    create or replace procedure del_ename(deleName in varchar2)
    
    is
        cnt number;
        total number;
    begin
        --사원이름 조회 유1 무0
        select count(ename) into cnt 
        from emp3
        where ename = delename;
    
        if cnt>0 -- 존재한다면
            then
            delete from emp3
            where ename = deleName;
    
            commit;
    
            select count(*) into total
            from emp3;
    
            dbms_output.put_line('#'|| deleName ||' 사원이 삭제되었습니다. 총 사원은  '|| total ||'입니다.');
    
        else
            select count(*) into total
            from emp3;
            dbms_output.put_line('#'|| deleName ||' 사원이 존재하지 않고. 총 사원은  '|| total ||'입니다.');
    
    
  end if; 

end;
/

show errors;

--============================================================
개선1) if then과 else select 문을 프로시저 내에 한번만 정의해서 출력
select count(*) into total
from emp3;

개선2)
del_ename('ADAMS')
del_enmae('adams') 상관없이 일치하는 사원 삭제

create or replace procedure del_ename(deleName in varchar2)
is
cnt number;
total number;
begin
--사원이름 조회 유1 무0
select count(ename) into cnt
from emp3
where upper(ename) = upper(delename);

  select count(*) into total
  from emp3;

  if cnt>0 -- 존재한다면
      then
      delete from emp3
      where lower(ename) = lower(deleName);

      commit;

      dbms_output.put_line('#'|| deleName ||' 사원이 삭제되었습니다. 총 사원은  '|| (total-1) ||'입니다.');

  else
      dbms_output.put_line('#'|| deleName ||' 사원이 존재하지 않고. 총 사원은  '|| total ||'입니다.');


  end if; 

end;
/

show errors;




------

<Stored Function'> 저장함수

- 실행(함수 호출) 후 결과를 되돌려 받을 수 있는 return 데이터; 를 반드시 명시해야 함!

- 형식

  ```SQL
  CREATE OR REPLACE FUNCTION 함수명( 매개변수 선언 )
  RETURN 자료형
  IS
      변수선언
  BEGIN
      (순차적으로) 실행할 SQL문
      ...
      RETURN 데이터;
  END;
  /
  • 사용법

    1. CREATE FUNCTION~ (함수를 DB에 저장) --함수 생성
    2. VARIABLE 바인드 변수명; --변수 선언 
    3. EXEC[UTE] : 바인드변수명 := 함수명() -- 함수호출, 결과값 저장
    4. PRINT 바인드변수명; --저장값 확인
  • 참고

          void hello(String  name){
             System.out.println("안녕,"+name);
          }       
               hello();
          -----> Stored Procedure (리턴키워드 없고)
    
          String hi( ){
             return "좋은 하루~!!";
          }      
              String msg =   hi();
          -----> Stored Function (리턴키워드 있고)
  • 문제

    문제)
    특정 사원에게 보너스를 지급하려고 하는데 급여의 200%에 해당하는 비용을 지급하려 한다. 이 보너스 금액을 FUNCTION을 통해 구하시오
    --> fun_test.sql
    --> 함수명 : call_bonus('SMITH');
    CREATE OR REPLACE FUNCTION call_bonus( vename emp.ename%type )
    return number
    IS
    
        sal emp.sal%type;
        bonus number;
    BEGIN
        SELECT sal INTO sal -- 컬렴명 sal, 변수명 vsal
        FROM emp
        WHERE ename = vename;
        --SELECT 문의 ';' 끝난 후 컬럼명은 사라지고 변수명만 남는다.
        --SELECT는 죽어서 변수명을 남긴다!
    
        --보너스 계산
        bonus := sal*2;
    
        return bonus; --프로시저와 다르게 펑션은 반드시 리턴값이 지정되어야 함.
    END;
    /
    
    

--=========================================================

문제) call_bonus2 Function을 정의하고 매개변수로 1.사원명과 보너스 비율을 넣어서 보너스 금액을 리턴하시오

exec :bonus := call_bonus('SMITH', 200)
print bonus











궁금상자

  • select into가 헷갈려
    원본은 있고 대상 테이블 새롭게 생성하려고 할때, 그럼 테이블 create 로 하면 되는데 왜 selet into로 하는거지?...
    부분적으로 원본테이블을 가져오려고 할때?

  • 그럼 select into 와 insert into는?
    select into는 타겟테이블이 실제로 존재하지 않아도 된다,
    반면 insert into는 타겟테이블이 존재해야 하고,

+ Recent posts