😀 패키지(PACKAGE)


  - 패키지는 논리적 관련성이 있는 PL/SQL 변수,상수,커서,서브프로그램 등을 묶어 놓은 객체
  - 컴파일되어 저장되며 다른 프로그램에서 패키지의 항목을 참조,공유, 실행할 수 있음
  - 모듈화 기능제공
  - 프로그램 설계의 용이성 제공:선언부와 실행부를 서로 다른 프로그램으로 구성
  - 캡슐화 기능제공-정보의 은닉성이 확보


 1)패키지의 구조
  - 패키지는 선언부와 본문으로 구성됨


  1)선언부
   - 패키지의 명세(Specification)
   - 패키지에 사용할 변수,상수,커서,서브프로그램의 선언부 만으로 구성 --서브프로그램:트리거,프로시져,함수 등등
   - 자바의 interface와 유사

(사용형식)
    CREATE [OR REPLACE] PACKAGE 패키지명 IS
     변수,상수,커서 등의 선언;
     
     FUNCTION 함수명(
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
       RETURN 타입명;
       
      PROCEDURE 프로시져명 
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
       
   END [패키지명];

1)본문부
   - 패키지에 사용할 변수,상수,커서,서브프로그램으로 구성
   - 세부적인 구현부분 포함
   - 패키지의 본문은 패키지의 소유자만 접근하여 수정 가능

(사용형식)
    CREATE [OR REPLACE] PACKAGE BODY 패키지명 IS
     변수,상수,커서 등의 선언;
     
     FUNCTION 함수명(
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
       RETURN 타입명;
     IS
     
     BEGIN
        실행부
        RETURN expr;
     END 함수명; 
       
      PROCEDURE 프로시져명(
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
     IS
     
     BEGIN
     
     END 프로시져명;
       
   END [패키지명];

사용예)EMP 테이블에서 사원번호를 입력받아 사원정보(이름, 부서명, 직무코드)를 조회하는 함수,
      신입사원정보를 저장하는 프로시져, 퇴직자를 처리하는 프로시져를 포함하는 패키지를 hrd_pkg로 구성하시오.

(선언부)
    CREATE OR REPLACE PACKAGE hrd_pkg IS
    
    -- 사원번호를 입력받아 사원정보(이름, 부서명, 직무코드)를 조회하는 함수
    FUNCTION fn_getinfo_emp(
        p_eid IN EMP.EMP_ID%TYPE)
        RETURN VARCHAR2;
        
    -- 신입사원정보를 저장하는 프로시져.
    PROCEDURE new_emp_proc(

        p_pname IN EMP.EMP_NAME%TYPE,

        p_did IN EMP.DEPT_ID%TYPE);
        
        
    -- 퇴직자를 처리하는 프로시져
    PROCEDURE retire_emp_proc(
     p_pid IN EMP.EMP_ID%TYPE);
     
  END hrd_pkg;
(본문부)
    CREATE OR REPLACE PACKAGE BODY hrd_pkg IS
    
    -- 사원번호를 입력받아 사원정보(이름, 부서명, 직무코드)를 조회하는 함수
    FUNCTION fn_getinfo_emp(
        p_eid IN EMP.EMP_ID%TYPE)
        RETURN VARCHAR2
       IS
         L_ENAME EMP.EMP_NAME%TYPE;
         L_DNAME DEPARTMENTS.DEPARTMENT_NAME%TYPE;
         L_JID EMP.JOB_ID%TYPE;
         L_RES VARCHAR2(500); -- 반환할 정보 저장
       BEGIN
         SELECT A.EMP_NAME,B.DEPARTMENT_NAME,A.JOB_ID INTO L_ENAME,L_DNAME,L_JID
           FROM EMP A, DEPARTMENTS B
          WHERE A.EMP_ID=p_eid
            AND A.DEPT_ID=B.DEPARTMENT_ID; --조인
          L_RES:=p_eid||' '||L_ENAME||' '||L_DNAME||' '||L_JID;  
          RETURN L_RES;
       END fn_getinfo_emp;
        
    -- 신입사원정보를 저장하는 프로시져.
    PROCEDURE new_emp_proc(
        p_pname IN EMP.EMP_NAME%TYPE,
        p_did IN EMP.DEPT_ID%TYPE)
        IS
          L_EID EMP.EMP_ID%TYPE;
        BEGIN
          SELECT MAX(EMP_ID)+1 INTO L_EID
            FROM EMP;
            
           INSERT INTO EMP(EMP_ID,EMP_NAME,HIRE_DATE,DEPT_ID)
            VALUES(L_EID, p_pname, SYSDATE, p_did);
            
            COMMIT;
            
        END new_emp_proc;
        
        
    -- 퇴직자를 처리하는 프로시져
    PROCEDURE retire_emp_proc(
     p_pid IN EMP.EMP_ID%TYPE)
     IS
        L_NAME EMP.EMP_NAME%TYPE;
        L_HDATE DATE;
        L_JID JOBS.JOB_ID%TYPE;
        L_DID EMP.DEPT_ID%TYPE;
        L_CNT NUMBER:=0;
        L_NO_DATA EXCEPTION; 
     BEGIN
        SELECT COUNT(*) INTO L_CNT
          FROM EMP
         WHERE EMP_ID=p_pid;
         
         IF L_CNT != 0 THEN
            SELECT EMP_NAME, HIRE_DATE, JOB_ID, DEPT_ID 
            INTO L_NAME, L_HDATE, L_JID, L_DID
            FROM EMP
            WHERE EMP_ID=p_pid; 
           
           INSERT INTO RETIRE VALUES (p_pid, L_NAME, L_HDATE, L_JID, L_DID);
           
           DELETE FROM EMP WHERE EMP_ID=p_pid;
           
           
         ELSE
           RAISE L_NO_DATA;
          END IF; 
          
          COMMIT;
          
          EXCEPTION WHEN L_NO_DATA THEN
           DBMS_OUTPUT.PUT_LINE(p_pid||'사원정보가 없습니다. ');
           ROLLBACK;
           
     END retire_emp_proc;

     
  END hrd_pkg;
[실행]  
  SELECT EMP_ID AS 사원번호,
         HRD_PKG.FN_GETINFO_EMP(EMP_ID) AS 사원정보
    FROM EMP
   WHERE DEPT_ID = 60; 

[실행] 신규사원등록
  사원명 =>'홍길순', 부서코드=>100
  EXECUTE hrd_pkg.new_emp_proc('홍길순',100);
  
[실행] 퇴직자처리
  사원번호 => 145  
  EXECUTE hrd_pkg.retire_emp_proc(145);

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 패키지 221202-03  (0) 2022.12.02
[ORACLE] 트리거 221202-02  (0) 2022.12.02
[ORACLE] 함수 221202-01  (0) 2022.12.02
[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 반복문 221201-03  (0) 2022.12.01

❗패키지(PACKAGE)


  - 패키지는 논리적 관련성이 있는 PL/SQL 변수,상수,커서,서브프로그램 등을 묶어 놓은 객체
  - 컴파일되어 저장되며 다른 프로그램에서 패키지의 항목을 참조,공유, 실행할 수 있음
  - 모듈화 기능제공
  - 프로그램 설계의 용이성 제공:선언부와 실행부를 서로 다른 프로그램으로 구성
  - 캡슐화 기능제공-정보의 은닉성이 확보


 1)패키지의 구조
  - 패키지는 선언부와 본문으로 구성됨


  1)선언부
   - 패키지의 명세(Specification)
   - 패키지에 사용할 변수,상수,커서,서브프로그램의 선언부 만으로 구성 --서브프로그램:트리거,프로시져,함수 등등
   - 자바의 interface와 유사

 (사용형식)
    CREATE [OR REPLACE] PACKAGE 패키지명 IS
     변수,상수,커서 등의 선언;
     
     FUNCTION 함수명(
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
       RETURN 타입명;
       
      PROCEDURE 프로시져명 
       매개변수 IN|OUT|INOUT 데이터타입[:=default],
               :
       매개변수 IN|OUT|INOUT 데이터타입[:=default])
       
   END [패키지명];

 

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 패키지 221202-03  (0) 2022.12.05
[ORACLE] 트리거 221202-02  (0) 2022.12.02
[ORACLE] 함수 221202-01  (0) 2022.12.02
[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 반복문 221201-03  (0) 2022.12.01

❗ 트리거(TRIGGER)


 - 어떤 이벤트가 발생되면 자동적으로 다른 테이블의 변경동작이 수행 시키는
   일종의 프로시져
 - 자동적으로 실행되며 수동으로 실행시킬 수 없음
 - 트리거 대상 테이블에는 트리거 내용이 존재할 수 없음
 - 트렌젝션의 일부로 처리됨. 따라서 트리거 내부에 COMMIT,ROLLBACK,SAVEPOINT 등이
   존재할 수 없음

(사용형식)
  CREATE [OR REPLACE] TRIGGER 트리거이름
    BEFORE|AFTER INSERT|DELETE|UPDATE
    ON 테이블명
    [FOR EACH ROW]
    [WHERE 조건]
   [DECLARE]
     [선언영역]
   BEGIN
     트리거 본문;
   END;
  •   트리거 타이밍 : 트리거 본문이 실행되는 시점으로 BEFORE 또는 AFTER 사용
  •   이벤트 : 트리거 본문을 실행시키는 원인이 되는 DML명령으로 OR연산자로   조합 사용 가능
  •  트리거 종류 
         - 문장단위 트리거 : 'FOR EACH ROW'가 생략된 트리거로 DML명령의 결과에 포함된 행의 수와
           관계없이 한번만 실행되는 트리거 -- WHEN 조건 사용X
         - 행단위 트리거 :  'FOR EACH ROW'가 기술한 트리거로 DML명령의 결과에 포함된 행의 수 만큼
           트리거 수행, :OLD, :NEW 의사레코드 사용가능
  •  트리거 조건 : 'WHEN 조건'로 기술되며, 트리거 발생에 좀 더 구체적인 조건을 제시할 때 사용   
  •  트리거 의사레코드와 트리거 함수
 - 의사레코드
    -------------------------------------------------------------------------
       의사레코드         내용
    -------------------------------------------------------------------------
       :NEW             이벤트가 INSERT, UPDATE일 때 사용되며 새롭게
                        입력(신규 입력이나 갱신을 위한 값)되는 행을 지칭
                        DELETE에 사용되면 모든 열이 NULL로 SETTING
       :OLD             이벤트가 DELETE, UPDATE일 때 사용되며 삭제 또는 갱신의
                        대상이 되는 행을 지칭
                        INSERT에 사용되면 모든 열이 NULL로 SETTING     
    - 트리거 함수 : 이벤트를 OR연산자로 구성한 경우 이벤트의 종류를 구분하기 위한 함수
    --------------------------------------------------------------------------
       함수              내용
    --------------------------------------------------------------------------
     INSERTING          이벤트가 INSERT 이면 true 반환
     UPDATING           이벤트가 UPDATE 이면 true 반환
     DELETING           이벤트가 DELETE 이면 true 반환

✔사용예) LPROD테이블에서 LPROD_ID가 12번인 자료를 삭제하고 삭제 후 '자료삭제 성공'이라는
               메시지를 출력하는 트리거 작성

CREATE OR REPLACE TRIGGER tg_delete_lprod
    AFTER DELETE ON LPROD 
   BEGIN
     DBMS_OUTPUT.PUT_LINE('자료삭제 성공');
   END;
   
   DELETE FROM LPROD WHERE LPROD_ID >=10;
   SELECT * FROM LPROD;

** HR계정의 EMPLOYEES 테이블에서 사원번호,사원명,입사일,직무코드를 조회하여
   EMP테이블을 생성하시오 

CREATE TABLE EMP AS
    SELECT EMPLOYEE_ID AS EMP_ID,
           EMP_NAME,
           HIRE_DATE,
           JOB_ID,
           DEPARTMENT_ID AS DEP_ID
      FROM HR.EMPLOYEES; 

COMMIT;

** HR계정의 EMP테이블을 복사하여 RETIRE 테이블을 생성하시오 모든 자료는 삭제

CREATE TABLE RETIRE AS 
    SELECT * FROM EMP;
   
  DELETE FROM RETIRE;

✔사용예) EMP테이블에서 사원번호 121~125번 사원을 삭제하시오. 단 삭제전 해당사원의 자료를
                RETIRE 테이블에 저장하시오

CREATE OR REPLACE TRIGGER tg_delete_emp
    BEFORE DELETE OR UPDATE ON EMP
    FOR EACH ROW
  BEGIN
    INSERT INTO RETIRE VALUES(:OLD.EMP_ID,:OLD.EMP_NAME,:OLD.HIRE_DATE,
                              :OLD.JOB_ID,:OLD.DEP_ID);
  END;
  
  DELETE FROM EMP WHERE EMP_ID =121 AND EMP_ID<=125;

✔ 사용예)장바구니에 입력,수정,삭제가 발생되었을때 재고 수불테이블에 재고 변경을
               수행하는 트리거를 작성하시오.

CREATE OR REPLACE TRIGGER tg_cart_change
    AFTER INSERT OR UPDATE OR DELETE ON CART
    FOR EACH ROW
   DECLARE
     L_QTY NUMBER:=0;
     L_PID PROD.PROD_ID%TYPE;
     L_DATE DATE;
   BEGIN
     IF INSERTING THEN
        L_QTY:=(:NEW.CART_QTY); 
        L_PID:=(:NEW.CART_PROD);
        L_DATE:=TO_DATE(SUBSTR(:NEW.CART_NO,1,8));
     ELSIF UPDATING THEN
        L_QTY:=(:NEW.CART_QTY-:OLD.CART_QTY); 
        L_PID:=(:NEW.CART_PROD);
        L_DATE:=TO_DATE(SUBSTR(:NEW.CART_NO,1,8));
     ELSIF DELETING THEN
        L_QTY:=-(:OLD.CART_QTY); 
        L_PID:=(:OLD.CART_PROD);
        L_DATE:=TO_DATE(SUBSTR(:OLD.CART_NO,1,8));
     END IF;   
        UPDATE REMAIN A
           SET A.REMAIN_O=A.REMAIN_O+L_QTY,
               A.REMAIN_J_99=A.REMAIN_J_99-L_QTY,
               A.REMAIN_DATE=L_DATE
         WHERE A.REMAIN_YEAR='2020'
           AND A.PROD_ID=L_PID;
           
        EXCEPTION
          WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('예외발생'||SQLERRM);
   END;
   
   EXECUTE insert_cart_proc('b001',SYSDATE,'P201000001',10);
  
   UPDATE CART
      SET CART_QTY = 15
    WHERE CART_PROD='P201000001'
      AND CART_NO = '2022120200003';
    
   DELETE FROM CART
    WHERE CART_PROD='P201000001'
      AND CART_NO = '2022120200003';

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 패키지 221202-03  (0) 2022.12.05
[ORACLE] 패키지 221202-03  (0) 2022.12.02
[ORACLE] 함수 221202-01  (0) 2022.12.02
[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 반복문 221201-03  (0) 2022.12.01

❗함수(User Defined Function : Function)


 - 특징은 procedure와 유사하며, 반환 값이 존재함
 - 보통 OUT 매개변수는 사용하지 않음

(사용형식)
  CREATE [OR REPLACE] PROCEDURE 프로시져명[( 
    매개변수 [IN|OUT|INOUT] 데이터타입[:=디폴트 값],
            :
    매개변수 [IN|OUT|INOUT] 데이터타입[:=디폴트 값]) 
    RETURN 데이터타입 -- 세미콜론(;) 없음
  IS|AS 
    선언영역
  BEGIN
    실행영역
    (반드시 하나이상의 
      RETURN expr; 이 존재해야 함) --SELECT문의 SELECT절이나 WHERE절에서 사용, 동일한 데이터타입을 사용해야 함
  END;

  . 하나의 함수는 하나의 값만 반환 가능
  . 함수의 호출을 SELECT문의 SELECT절, WHERE절 등에서 수행

 

✔ 사용예) 회원번호를 입력받아 2020년 7월 구매현황을 조회하시오. 

CREATE OR REPLACE FUNCTION fn_sum_member(
    p_mid IN MEMBER.MEM_ID%TYPE)
    RETURN NUMBER --;x
  IS
    L_SUM NUMBER:=0; --구매금액을 계산해서 보관할 방, 값이없으면 NULL
  BEGIN
    SELECT SUM(A.CART_QTY*B.PROD_PRICE) INTO L_SUM
      FROM CART A, PROD B
     WHERE A.CART_PROD=B.PROD_ID
       AND A.CART_MEMBER=p_mid
       AND A.CART_NO LIKE '202007%';
    RETURN L_SUM;
  END;  
  
[실행] 
  SELECT MEM_ID AS 회원번호,
         MEM_NAME AS 회원명,
         NVL(fn_sum_member(MEM_ID),0) AS 구매금액
    FROM MEMBER     
   WHERE MEM_ID IN(SELECT CART_MEMBER
                     FROM CART
                    WHERE CART_NO LIKE '202007%'); 
  -- => OUTER JOIN 결과

✔사용예) 장바구니테이블에 매출정보를 저장하는 프로시져를 작성하시오
                입력자료는 회원번호,회원명,날짜,상품번호,수량이며 장바구니번호는 함수를 이용하여 
                작성하시오

CREATE OR REPLACE PROCEDURE insert_cart_proc(
    p_mid IN MEMBER.MEM_ID%TYPE,
    p_date IN DATE,
    p_pid IN PROD.PROD_ID%TYPE,
    p_qty IN NUMBER)
  IS 
   
  BEGIN
   
    
    INSERT INTO CART VALUES(p_mid,create_cart_no(p_date,p_mid),p_pid,p_qty);
    COMMIT;
  END;
  
--장바구니번호 생성 함수
  CREATE OR REPLACE FUNCTION create_cart_no(
    p_date IN DATE, p_mid IN MEMBER.MEM_ID%TYPE)
    RETURN CHAR
  IS
    L_CART_NO CART.CART_NO%TYPE; --장바구니번호 잠시보관
    L_MID MEMBER.MEM_ID%TYPE;
    L_COUNT NUMBER:=0; --행의수
    L_FLAG CHAR(9):=TO_CHAR(p_date,'YYYYMMDD')||'%';
  BEGIN
    --해당일자의 장바구니테이블에 자료존재 판단 
    SELECT COUNT(*) INTO L_COUNT
      FROM CART
     WHERE CART_NO LIKE L_FLAG;
    IF L_COUNT=0 THEN -- 첫 고객
       L_CART_NO:=TO_CHAR(p_date,'YYYYMMDD')||TRIM('00001');
    ELSE
      --해당 날짜의 최대장바구니번호
      SELECT MAX(CART_NO) INTO L_CART_NO
        FROM CART
       WHERE CART_NO LIKE L_FLAG; 
      -- 최대장바구니 번호를 보유한 회원번호 
      SELECT DISTINCT CART_MEMBER INTO L_MID 
        FROM CART
       WHERE CART_NO = L_CART_NO; 
       
      IF L_MID!=p_mid THEN
         L_CART_NO:=L_CART_NO+1;
      END IF;
    END IF; 
  
    RETURN L_CART_NO;
  END;

SELECT create_cart_no(TO_DATE('20200414'),'f001')
  FROM DUAL;
  /*
    p_mid IN MEMBER.MEM_ID%TYPE,
    p_date IN DATE,
    p_pid IN PROD.PROD_ID%TYPE,
    p_qty IN NUMBER)
  */
  
  EXECUTE insert_cart_proc('b001',SYSDATE,'P201000010',5);
  EXECUTE insert_cart_proc('b001',SYSDATE,'P302000016',10);
  EXECUTE insert_cart_proc('t001',SYSDATE,'P101000003',2);
 DELETE FROM CART WHERE CART_NO LIKE '2022%';
 COMMIT;

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 패키지 221202-03  (0) 2022.12.02
[ORACLE] 트리거 221202-02  (0) 2022.12.02
[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 반복문 221201-03  (0) 2022.12.01
[ORACLE] 분기명령 221201-02  (0) 2022.12.01

😀저장 프로시져(Stored Procedure: Procedure)


 - 특정 결과를 산출할 수 있는 모듈을 작성하고 컴파일하여 서버의 프로시져캐쉬에 저장
   하여 사용
 - 모든 응용프로그램에서 사용할 수 있도록 캡슐화 기능제공 =>일관성 제공
 - 데이터베이스 내부 구조에 대한 보안성 제공
 - 프로시져는 반환 값이 없음

(사용형식)
  CREATE [OR REPLACE] PROCEDURE 프로시져명[( 
    매개변수 [IN|OUT|INOUT] 데이터타입[:=디폴트 값], --IN 프로시져 밖에서 안으로,OUT 안에서 밖으로 INOUT 둘다가능/ 생략하면 IN
            :
    매개변수 [IN|OUT|INOUT] 데이터타입[:=디폴트 값]) --데이터타입은 타입명만 입력하고 크기는 입력하지 않는다
  IS|AS --DECLARE랑 똑같음
    선언영역
  BEGIN
    실행영역
  END;

✔수행예) 직무코드,직무명,최대급여,최소급여를 입력 받아 HR계정의 JOBS테이블에 신규 데이터를
              삽입하는 프로시져를 작성하시오. --다른계정에서 만들 수 없음

 CREATE OR REPLACE PROCEDURE insert_jobs_proc(
    p_job_id IN HR.JOBS.JOB_ID%TYPE,--매개변수는 보통 P를 사용하는게 일반적
    p_job_title IN HR.JOBS.JOB_TITLE%TYPE,
    p_misal IN NUMBER, 
    p_mxsal IN NUMBER)
  IS
  
  BEGIN
   INSERT INTO HR.JOBS VALUES( p_job_id,p_job_title,p_misal,p_mxsal);
   COMMIT;
  END;

[프로시져의 실행]
 1. 독립적 실행
  - OUT 매개변수를 사용하지 않은 경우
    EXEC|EXECUTE 프로시져명(매개변수list);
 2. PL/SQL의 블록에서 실행   
  - OUT 매개변수를 사용한 경우 - OUT매개변수에 의해 전달되는 값을 보관항 변수를 사용
    프로시져명(매개변수list)

 EXECUTE insert_jobs_proc('sample1','SAMPLE JOB TITLE',3000,5000);

✔사용예)직무코드를 입력받아 해당 자료를 JOBS테이블에서 삭제하는 프로시져 작성

 CREATE OR REPLACE PROCEDURE delete_jobs_proc(
    p_job_id IN JOBS.JOB_ID%TYPE)
   IS
    L_CNT NUMBER:=0;   
   BEGIN
     SELECT COUNT(*) INTO L_CNT
       FROM HR.JOBS
      WHERE JOB_ID=p_job_id;
      
      IF L_CNT!=0 THEN
         DELETE FROM HR.JOBS WHERE JOB_ID=p_job_id;
      ELSE
         DBMS_OUTPUT.PUT_LINE('해당자료가 테이블에 없습니다..');
      END IF;
      COMMIT;
   END;
   
   EXEC delete_jobs_proc('sample1');

✔사용예)오늘이 2020년 7월 28일 이라고 가정하고 매출정보를 장바구니에 저장하는 프로시져를
                작성하시오. 입력 값은 회원번호,오늘날짜,상품코드,수량이다

  CREATE OR REPLACE PROCEDURE delete_jobs_proc(
    p_job_id IN JOBS.JOB_ID%TYPE)
  IS  
    L_CNT NUMBER:=0;
  BEGIN
    SELECT COUNT(*) INTO L_CNT
      FROM HR.JOBS
     WHERE JOB_ID=p_job_id;
    
    IF L_CNT!=0 THEN
       DELETE FROM HR.JOBS WHERE JOB_ID=p_job_id;
    ELSE
       DBMS_OUTPUT.PUT_LINE('해당자료가 테이블에 없습니다..');
    END IF;
    COMMIT;
  END;
      
      
  EXEC delete_jobs_proc('sample1');

✔사용예) 오늘이 2020년 7월 28일리라고 가정하고 매출정보를 장바구니에 저장하는 프로시져를
                작성하시오. 입력 값은 회원번호,오늘날짜,상품코드,수량이다

CREATE OR REPLACE PROCEDURE delete_jobs_proc(
    p_job_id IN JOBS.JOB_ID%TYPE)
  IS  
    L_CNT NUMBER:=0;
  BEGIN
    SELECT COUNT(*) INTO L_CNT
      FROM HR.JOBS
     WHERE JOB_ID=p_job_id;
    
    IF L_CNT!=0 THEN
       DELETE FROM HR.JOBS WHERE JOB_ID=p_job_id;
    ELSE
       DBMS_OUTPUT.PUT_LINE('해당자료가 테이블에 없습니다..');
    END IF;
    COMMIT;
  END;
      
      
  EXEC  delete_jobs_proc('sample1');

✔사용예)오늘이 2020년 7월 28일리라고 가정하고 매출정보를 장바구니에 저장하는 프로시져를
              작성하시오. 입력 값은 회원번호,오늘날짜,상품코드,수량이다

 CREATE OR REPLACE PROCEDURE insert_cart_proc(
    p_mid IN MEMBER.MEM_ID%TYPE,
    p_date IN DATE,
    p_pid IN PROD.PROD_ID%TYPE,
    p_qty IN NUMBER)
  IS 
    L_CART_NO CART.CART_NO%TYPE;
    L_FLAG CHAR(9):=TO_CHAR(p_date,'YYYYMMDD')||'%';
    L_CNT NUMBER:=0;
  BEGIN
    SELECT COUNT(*) INTO L_CNT
      FROM CART
     WHERE CART_NO LIKE L_FLAG;
    
    IF L_CNT=0 THEN 
       L_CART_NO:=TO_CHAR(p_date,'YYYYMMDD')||TRIM('00001');
    ELSE 
       SELECT MAX(CART_NO)+1 INTO L_CART_NO
         FROM CART
        WHERE CART_NO LIKE L_FLAG; 
    END IF;
    
    INSERT INTO CART VALUES(p_mid,L_CART_NO,p_pid,p_qty);
    COMMIT;
  END;
      
  EXECUTE  insert_cart_proc('a001',TO_DATE('20200728'),'P201000008',5);

 

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 트리거 221202-02  (0) 2022.12.02
[ORACLE] 함수 221202-01  (0) 2022.12.02
[ORACLE] 반복문 221201-03  (0) 2022.12.01
[ORACLE] 분기명령 221201-02  (0) 2022.12.01
[ORACLE] 커서(CURSOR) 2221201-01  (0) 2022.12.01

😊반복문


 - 오라클의 반복문은 LOOP, WHILE, FOR문이 제공됨
 - 주로 커서를 위한 명령으로 사용됨
 1. LOOP문
  - 반복문의 기본 구조 제공
  - 무한루프 

(사용형식)
  LOOP
   반복처리명령문(들);
   [EXIT WHEN 조건;]
   [반복처리명령문(들);]
  END LOOP; 
   .'EXIT WHEN 조건' : 조건을 평가하여 결과가 참(true)이면 반복을 벗어남

✔사용예) 구구단을 5단을 출력하는 블록생성

DECLARE
    L_CNT NUMBER:=0;
  BEGIN
    LOOP
      L_CNT:=L_CNT+1;
      EXIT WHEN L_CNT >=10;
      DBMS_OUTPUT.PUT_LINE('5 * '||L_CNT||' = '||5*L_CNT);
     END LOOP; 
  END;

✔사용예) 회원의 주소지가 '충남'인 회원들의 2020년 상반기 구매액으로 조회하는 익명블록을
                작성하시오. 출력사항은 회원번호,회원명,주소,구매금액

(PL/SQL을 사용하지 않은 경우)
 SELECT M.MEM_ID AS 회원번호,
        M.MEM_NAME AS 회원명,
        M.MEM_ADD1||' '||M.MEM_ADD2 AS 주소,
        A.CSUM AS 구매금액
   FROM MEMBER M,
        (SELECT C.CART_MEMBER AS CID,
                SUM(C.CART_QTY*P.PROD_PRICE) AS CSUM
           FROM CART C, PROD P
          WHERE C.CART_PROD=P.PROD_ID
            AND SUBSTR(C.CART_NO,1,6) BETWEEN '202001' AND '202006'
          GROUP BY C.CART_MEMBER)A  -- 2020년 상반기 회원별 구매금액
  WHERE M.MEM_ID=A.CID
    AND M.MEM_ADD1 LIKE '충남%';
   
  (PL/SQL)  
  DECLARE -- 출력사항
    L_MID MEMBER.MEM_ID%TYPE;
    L_MNAME VARCHAR2(100);
    L_ADDR VARCHAR2(500);
    L_SUM NUMBER:=0;
    CURSOR CUR_MEM_ADD IS
      SELECT MEM_ID, MEM_NAME,MEM_ADD1||' '||MEM_ADD2
        FROM MEMBER
       WHERE MEM_ADD1 LIKE '충남%'; 
  BEGIN
    OPEN CUR_MEM_ADD;
    LOOP
      FETCH CUR_MEM_ADD INTO L_MID,L_MNAME,L_ADDR; --커서 집합에 들어있는 변수
      EXIT WHEN CUR_MEM_ADD%NOTFOUND;
      SELECT SUM(A.CART_QTY*B.PROD_PRICE) INTO L_SUM
        FROM CART A, PROD B
       WHERE A.CART_PROD=B.PROD_ID
        AND SUBSTR(A.CART_NO,1,6) BETWEEN '202001' AND '202006'
        AND A.CART_MEMBER=L_MID;
        
      DBMS_OUTPUT.PUT_LINE('회원번호 : '  ||L_MID);
      DBMS_OUTPUT.PUT_LINE('회원명 : '  ||L_MNAME);
      DBMS_OUTPUT.PUT_LINE('주  소  : '  ||L_ADDR);
      DBMS_OUTPUT.PUT_LINE('구매금액 : '  ||L_SUM);
      DBMS_OUTPUT.PUT_LINE('---------------------------------'); 
    END LOOP;
    CLOSE CUR_MEM_ADD;
  END;

2. WHILE문
  - JAVA의 WHILE문과 유사 기능

(사용형식)
  WHILE 조건 LOOP
    반복수행할 명령문(들);
  END LOOP;
  . '조건'이 true 이면 반복을 수행하고, false이면 반복처리를 하지 않음
  . 반복횟수가 중요하지 않거나, 반복횟수를 알 수 없는 경우
  . 반복종료의 조건을 알고 있는 경우

✔사용예)  구구단 5단을 출력하시오.

 DECLARE
    L_CNT NUMBER :=0;
  BEGIN
    WHILE L_CNT < 9 LOOP
      L_CNT:=L_CNT+1;
      DBMS_OUTPUT.PUT_LINE('5 * '||L_CNT||' = '||5 * L_CNT);
    END LOOP;
  END;

✔사용예) 회원의 주소지가 '충남'인 회원들의 2020년 상반기 구매액으로 조회하는 익명블록을
                작성하시오. 출력사항은 회원번호,회원명,주소,구매금액(WHILE 사용)

 DECLARE -- 출력사항
    L_MID MEMBER.MEM_ID%TYPE;
    L_MNAME VARCHAR2(100);
    L_ADDR VARCHAR2(500);
    L_SUM NUMBER:=0;
    CURSOR CUR_MEM_ADD IS
      SELECT MEM_ID, MEM_NAME,MEM_ADD1||' '||MEM_ADD2
        FROM MEMBER
       WHERE MEM_ADD1 LIKE '충남%'; 
  BEGIN
    OPEN CUR_MEM_ADD;
   FETCH CUR_MEM_ADD INTO L_MID,L_MNAME,L_ADDR; --커서 집합에 들어있는 변수 
   WHILE CUR_MEM_ADD%FOUND LOOP 
      
      SELECT SUM(A.CART_QTY*B.PROD_PRICE) INTO L_SUM
        FROM CART A, PROD B
       WHERE A.CART_PROD=B.PROD_ID
        AND SUBSTR(A.CART_NO,1,6) BETWEEN '202001' AND '202006'
        AND A.CART_MEMBER=L_MID;
        
      DBMS_OUTPUT.PUT_LINE('회원번호 : '  ||L_MID);
      DBMS_OUTPUT.PUT_LINE('회원명 : '  ||L_MNAME);
      DBMS_OUTPUT.PUT_LINE('주  소  : '  ||L_ADDR);
      DBMS_OUTPUT.PUT_LINE('구매금액 : '  ||L_SUM);
      DBMS_OUTPUT.PUT_LINE('---------------------------------'); 
      FETCH CUR_MEM_ADD INTO L_MID,L_MNAME,L_ADDR;
    END LOOP;
    CLOSE CUR_MEM_ADD;
  END;

3. FOR 문
 - JAVA의 FOR와 유사한 기능 제공
 - 반복횟수를 알고 있거나 반복횟수가 중요한 경우 사용

(일반 FOR문 사용형식) 
  FOR 인덱스 IN [REVERSE] 초기값...최종값 LOOP
    반복처리명령문(들);
  END LOOP;

. '인덱스' : 시스템에서 자동으로 확보하는 제어변수로 초기값에서 최종값까지 
    1씩 변하는 값을 보관
 . 'REVERSE' : 역순으로(최종값 -> 초기값) 인덱스값을 운용

 

✔사용예) 구구단의 5단을 출력

 DECLARE
  
  BEGIN
    FOR I IN 1..9 LOOP
      DBMS_OUTPUT.PUT_LINE('5 * '||I||' = '||5*I);
    END LOOP; 
    FOR I IN  REVERSE 1..9 LOOP
      DBMS_OUTPUT.PUT_LINE('5 * '||I||' = '||5*I);
    END LOOP;
  END;

커서용 FOR문 사용형식)

 FOR 레코드 IN 커서명|커서용SELECT문 LOOP --한 행을 지칭하는 포인터변수
     반복처리명령문(들);
  END LOOP;

. '커서명|커서용 SLELECT 문': 선언부에서 선언된 커서나 또는 커서를 구성하는 SELECT 문을
    in-line 서브쿼리로 사용할 수 있음
  . '레코드'는 시스템에서 확보해주며, 커서 내의 각행을 지칭하는 포인트 역활을 함
  . 커서의 각 열의 참조는 '레코드.열이름'형태를 사용하여 수행
  . 커서를 FOR문을 이용하면 OPEN,FETCH,CLOSE를 생략한다.

 

✔사용예)  회원의 주소지가 '충남'인 회원들의 2020년 상반기 구매액으로 조회하는 익명블록을
                 작성하시오. 출력사항은 회원번호,회원명,주소,구매금액(FOR 사용)  --커서와 가장 궁합이 잘 맞음

 DECLARE -- 구매금액
    L_SUM NUMBER:=0;
    CURSOR CUR_MEM_ADD IS
      SELECT MEM_ID,MEM_NAME,MEM_ADD1,MEM_ADD2
        FROM MEMBER
       WHERE MEM_ADD1 LIKE '충남%'; 
  BEGIN
   FOR REC IN CUR_MEM_ADD LOOP    
      SELECT SUM(A.CART_QTY*B.PROD_PRICE) INTO L_SUM
        FROM CART A, PROD B
       WHERE A.CART_PROD=B.PROD_ID
        AND SUBSTR(A.CART_NO,1,6) BETWEEN '202001' AND '202006'
        AND A.CART_MEMBER=REC.MEM_ID;
        
      DBMS_OUTPUT.PUT_LINE('회원번호 : '  ||REC.MEM_ID);
      DBMS_OUTPUT.PUT_LINE('회원명 : '  ||REC.MEM_NAME);
      DBMS_OUTPUT.PUT_LINE('주  소  : '  ||REC.MEM_ADD1||' '||REC.MEM_ADD2);
      DBMS_OUTPUT.PUT_LINE('구매금액 : '  ||L_SUM);
      DBMS_OUTPUT.PUT_LINE('---------------------------------'); 
    END LOOP;
  END;  
--------------------------------------------------------------------------  
  DECLARE -- 구매금액
    L_SUM NUMBER:=0;
  BEGIN
   FOR REC IN (SELECT MEM_ID,MEM_NAME,MEM_ADD1,MEM_ADD2
                 FROM MEMBER
                WHERE MEM_ADD1 LIKE '충남%') LOOP    
      SELECT SUM(A.CART_QTY*B.PROD_PRICE) INTO L_SUM
        FROM CART A, PROD B
       WHERE A.CART_PROD=B.PROD_ID
        AND SUBSTR(A.CART_NO,1,6) BETWEEN '202001' AND '202006'
        AND A.CART_MEMBER=REC.MEM_ID;
        
      DBMS_OUTPUT.PUT_LINE('회원번호 : '  ||REC.MEM_ID);
      DBMS_OUTPUT.PUT_LINE('회원명 : '  ||REC.MEM_NAME);
      DBMS_OUTPUT.PUT_LINE('주  소  : '  ||REC.MEM_ADD1||' '||REC.MEM_ADD2);
      DBMS_OUTPUT.PUT_LINE('구매금액 : '  ||L_SUM);
      DBMS_OUTPUT.PUT_LINE('---------------------------------'); 
    END LOOP;
  END;

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 함수 221202-01  (0) 2022.12.02
[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 분기명령 221201-02  (0) 2022.12.01
[ORACLE] 커서(CURSOR) 2221201-01  (0) 2022.12.01
[ORACLE] PL/SQL 221130-04  (1) 2022.11.30

분기명령
 - PL/SQL에서 제공되는 분기문에는 IF, CASE WHEN ~ THEN이 존재 함
1) IF문
 - 개발언어의 IF문과 동일 기능 제공

(사용형식 - 1)
  IF 조건문 THEN
     명령문1;
  [ELSE
       명령문2;]
   END IF;
 
(사용형식-2)
  IF 조건문1 THEN
     명령문1;
  ELSIF 조건문2 THEN --ELSEIF X
     명령문2;
       :
  ELSE
     명령문n;
  END IF;   
  
(사용형식-3)
  IF 조건문1 THEN
     IF 조건문2 THEN
        명령문1;
     ELSE
        명령문2;
     END IF;  
   ELSIF 조건문3 THEN
      명령문3;
        :
   ELSE
      명령문n;
   END IF;

✔사용예) 년도를 입력받아 윤년과 평년을 구별하는 블록을 작성하시오.
               윤년 : ((4의 배수)이면서 (100의 배수가 아니거나)) (400의 배수)가 되는 해

ACCEPT P_YEAR PROMPT '년도입력(YYYY) : '
  DECLARE
    L_YEAR NUMBER:=TO_NUMBER('&P_YEAR');
    L_RES VARCHAR2(500);
  BEGIN
    IF (MOD(L_YEAR,4)= 0 AND MOD(L_YEAR,100)!=0) OR(MOD(L_YEAR,400)=0) THEN
        L_RES:=L_YEAR||'년은 윤년입니다.';
    ELSE    
        L_RES:=L_YEAR||'년은 평년입니다.'; 
    END IF;
    
    DBMS_OUTPUT.PUT_LINE(L_RES);    
  END;

 ✔사용예) 첫 날에 100원, 둘째날 부터 전날의 2배씩 저축할때 최초로 100만원을 넘는 날과
                 저축액수를 구하시오.

DECLARE
    L_SUM NUMBER:= 0; -- 저축 총액
    L_DAMT NUMBER:=100; --매일 저축할 액수
    L_DAYS NUMBER:= 1; --날수
  BEGIN
    LOOP
      L_SUM:=L_SUM+L_DAMT;
      IF L_SUM>=1000000 THEN
        EXIT;
      ELSE
        L_DAMT:=L_DAMT*2;
        L_DAYS:=L_DAYS+1;
      END IF;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('날수 : '||L_DAYS);
    DBMS_OUTPUT.PUT_LINE('저축액수 : '||L_SUM);
  END;

2) CASE WHEN ~ THEN
 - 다중분기문
 - JAVA의 SWITCH CASE문과 유사 기능 제공

(사용형식-1)
  CASE WHEN 조건1 THEN
            명령1;
       WHEN 조건2 THEN
            명령2;   
             :
       [ELSE 
             명령n;]
  END CASE;             
     
(사용형식-2)
  CASE 조건
       WHEN 값1 THEN
            명령1;
       WHEN 값2 THEN
            명령2;     
             :
      [ELSE
           명령n;]
  END CASE;

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 저장프로시져 221201-04  (1) 2022.12.01
[ORACLE] 반복문 221201-03  (0) 2022.12.01
[ORACLE] 커서(CURSOR) 2221201-01  (0) 2022.12.01
[ORACLE] PL/SQL 221130-04  (1) 2022.11.30
[ORACLE] INDEX 221130-03  (0) 2022.11.30

 

2. 커서(CURSOR)


 - 넓은 의미의 커서는 SQL명령의 영향을 받은 행들의 집합이고, 좁은의미로는 SELECT문의 결과 집합
   을 의미
 - 묵시적 커서(IMPLICITE CURSOR)와 명시적 커서(EXPLICITE CURSOR)
 - 커서는 Query의 결과에 대하여 수정,삭제,검색 할 수 있도록 해주는 도구
 - 개발자가 쿼리의 결과를 PL/SQL블록에서 수동으로 제한할 수 있도록 해줌
 - 커서의 사용 단계
   . 생성(선언영역) => OPEN (실행영역) => FETCH (실행영역 반복문 내부) => CLOSE (실행영역)
   -- OPEN,CLOSE는 한 번 사용, OPEN을 했으면 꼭 CLOSE까지 해주어야 함


 1)묵시적 커서 
   . 이름이 없는 커서로 일반적인 SELECT문의 결과 집합이 대표적인 묵시적 커서
   . 묵시적 커서는 결과가 출력되는 순간 OPEN 되고 출력이 완료되면 자동으로 CLOSE됨
     =>커서 내부에 접근이 불가능

❗커서속성

----------------------------------------------------------------------------------
     속성            내용
   ----------------------------------------------------------------------------------
    SQL%ISOPEN     커서가 OPEN 상태이면 true 반환(묵시적 커서는 항상 false) --커서를 만들 때 SQL 대신에 커서 이름을 넣으면 됨
    SQL%NOTFOUND   커서 내부에 FETCH할 자료가 있으면 false, 없으면 true
    SQL%FOUND      커서 내부에 FETCH할 자료가 없으면 false, 있으면 true  
    SQL%ROWCOUNT   커서 내부의 행의 갯수(결과의 수)

2)명시적 커서
    .선언영역에서 이름을 부여하여 선언한 커서

3)선언형식

CURSOR 커서명 [(변수명 타입명,...)] IS
     SELECT 문;


    . '(변수명 타입명,...)' : 커서에서 사용될 자료를 전달받는 매개변수로 타입명 기술시 크기를
      지정하지 않음
    . 매개변수에 값은 OPEN문에서 설정 함 
      
✔사용예)부서번호를 키보드로 입력 받아 해당 부서에 근무하는 직원들의 사원번호,사원명,입사일,직무코드를
               출력하시오.

 ACCEPT P_DCODE PROMPT '부서번호 입력(10~110) : ' -- ACCEPT 변수명 PROMPT 입력창 문구( ; 사용 X)
  DECLARE -- SELECT문에서 가져오는 것들은 변수가 필요
    L_EID HR.EMPLOYEES.EMPLOYEE_ID%TYPE; --데이터 타입이나 크기를 잘 모르 때 테이블 명으로 작성 
    L_ENAME VARCHAR2(80);
    L_HDATE DATE;
    L_JOB_ID HR.JOBS.JOB_ID%TYPE; 
    CURSOR CUR_EMP_NAME(DID HR.DEPARTMENTS.DEPARTMENT_ID%TYPE) IS -- OPEN 문의 변수는 ACCEPT 변수다
      SELECT EMPLOYEE_ID,EMP_NAME,HIRE_DATE,JOB_ID
        FROM HR.EMPLOYEES
       WHERE DEPARTMENT_ID = DID; 
  BEGIN
  
  END;

 4) OPEN문
  - 커서를 사용하기 위한 명령

 (사용형식)
   OPEN 커서명[(값1,...)]

. '(값1,...)' : 커서 선언문에 사용된 매개변수에 전달될 값을 기술

 

✔사용예)

 ACCEPT P_DCODE PROMPT '부서번호 입력(10~110) : ' 
  DECLARE 
    L_EID HR.EMPLOYEES.EMPLOYEE_ID%TYPE; 
    L_ENAME VARCHAR2(80);
    L_HDATE DATE;
    L_JOB_ID HR.JOBS.JOB_ID%TYPE; 
    CURSOR CUR_EMP_NAME(DID HR.DEPARTMENTS.DEPARTMENT_ID%TYPE) IS 
      SELECT EMPLOYEE_ID,EMP_NAME,HIRE_DATE,JOB_ID
        FROM HR.EMPLOYEES
       WHERE DEPARTMENT_ID = DID; 
  BEGIN
   OPEN CUR_EMP_NAME(TO_NUMBER('&P_DCODE')); -- OPEN 커서명 + OPEN 문의 변수는 ACCEPT 변수다
  END;

5)FETCH
  . 커서 내의 자료를 읽어 블록에 가져오는 명령
  . 보통 반복문 내부에 기술

(사용형식)
  FETCH 커서명 INTO 변수 list;

- 커서 SELECT 문의 SELECT절에 기술된 컬럼들을 차례대로 '변수list'에 할당
- 커서 속성을 이용하여 반복문을 벗어날 수 있음

✔사용예)

 ACCEPT P_DCODE PROMPT '부서번호 입력(10~110) : ' 
  DECLARE 
    L_EID HR.EMPLOYEES.EMPLOYEE_ID%TYPE; 
    L_ENAME VARCHAR2(80);
    L_HDATE DATE;
    L_JOB_ID HR.JOBS.JOB_ID%TYPE; 
    CURSOR CUR_EMP_NAME(DID HR.DEPARTMENTS.DEPARTMENT_ID%TYPE) IS 
      SELECT EMPLOYEE_ID,EMP_NAME,HIRE_DATE,JOB_ID
        FROM HR.EMPLOYEES
       WHERE DEPARTMENT_ID = DID; 
  BEGIN
   OPEN CUR_EMP_NAME(TO_NUMBER('&P_DCODE')); -- OPEN 커서명 + OPEN 문의 변수는 ACCEPT 변수다
   DBMS_OUTPUT.PUT_LINE('부서번호 : '||'&P_DCODE');
   DBMS_OUTPUT.PUT_LINE('================');
   LOOP 
     FETCH CUR_EMP_NAME INTO L_EID,L_ENAME,L_HDATE,L_JOB_ID;
     EXIT WHEN CUR_EMP_NAME%NOTFOUND;
     DBMS_OUTPUT.PUT_LINE('사원번호 : '||L_EID);
     DBMS_OUTPUT.PUT_LINE('사원명 : '||L_ENAME);
     DBMS_OUTPUT.PUT_LINE('입사일 : '||L_HDATE);
     DBMS_OUTPUT.PUT_LINE('직무코드 : '||L_JOB_ID);
     DBMS_OUTPUT.PUT_LINE('-------------------------------------');
  END LOOP; 
     DBMS_OUTPUT.PUT_LINE('&P_DCODE'||'번부서 직원 수 : '||CUR_EMP_NAME%ROWCOUNT||'명');
     DBMS_OUTPUT.PUT_LINE('  ');
 END;

6) CLOSE
  . OPEN된 커서는 CLOSE되어야 다시 OPEN 될 수 있음

 (사용형식)
   CLOSE 커서명;

'ORACLE 복습 & 정리' 카테고리의 다른 글

[ORACLE] 반복문 221201-03  (0) 2022.12.01
[ORACLE] 분기명령 221201-02  (0) 2022.12.01
[ORACLE] PL/SQL 221130-04  (1) 2022.11.30
[ORACLE] INDEX 221130-03  (0) 2022.11.30
[ORACLE] SEQUENCE,동의어 221130-02  (0) 2022.11.30

+ Recent posts