본문 바로가기
kosta/[DB]Oracle

[Oracle] SQL문 정리 5

by 엑츄얼리 2022. 3. 14.

Cursor

 - 질의 결과가 Multi Row일 경우 커서를 사용

DECLARE
   --커서선언
   CURSOR department_cursors IS
	SELECT department_id, department_name, location_id
	FROM departments;
   department_record department_cursors%ROWTYPE;

 BEGIN
  --커서 열기
  OPEN department_cursors;

  LOOP
     FETCH department_cursors
       INTO department_record.department_id,
	 department_record.department_name,
	 department_record.location_id;
      EXIT WHEN department_cursors%NOTFOUND;

      dbms_output.put_line(department_record.department_id ||'   '||
	department_record.department_name ||'    '||
	department_record.location_id);

  END LOOP;
 
  CLOSE department_cursors;

END;

 

 

Q. 커서를 이용하여 사원의 정보를 출력하라. 

    ( 사원번호, 사원이름(first_name), 급여, 급여누계 ) 

DECLARE
  CURSOR employee_cursors IS
	SELECT employee_id, first_name, salary
		FROM employees;
  
  employee_record employee_cursors%ROWTYPE;
  v_totalsalary NUMBER := 0;

BEGIN
  OPEN employee_cursors;

  dbms_output.put_line('======================');
  dbms_output.put_line('사원번호     사원이름      급여     급여누계');
  dbms_output.put_line('======================');

  LOOP
    FETCH employee_cursors INTO employee_record;
    EXIT WHEN employee_cursors %NOTFOUND;

    v_totalsalary := v_totalsalary + employee_record.salary;
     dbms_output.put_line(employee_record.employee_id ||'       '||
	employee_record.first_name ||'      '|| employee_record.salary ||'      '||
	v_totalsalary);
   END LOOP;
   CLOSE employee_cursors;

END;

 

 -- FOR..IN

 
DECLARE
  CURSOR employee_cursors IS
	SELECT employee_id, first_name, salary
		FROM employees;
  
  employee_record employee_cursors%ROWTYPE;
  v_totalsalary NUMBER := 0;

BEGIN
 
  dbms_output.put_line('======================');
  dbms_output.put_line('사원번호     사원이름      급여     급여누계');
  dbms_output.put_line('======================');

  FOR employee_record IN employee_cursors LOOP
    v_totalsalary := v_totalsalary + employee_record.salary;
    dbms_output.put_line(employee_record.employee_id ||'       '||
	employee_record.first_name ||'      '|| employee_record.salary ||'      '||
	v_totalsalary);
  END LOOP;

END;

 

 

Proceduer

 - 자주 사용하는 PL/SQL 블록을 재사용하기 위해  모듈화한 것

 

Q. 부서번호를 입력 받아 사원리스트를 출력

CREATE OR REPLACE PROCEDURE listByDeptno(p_deptno 
			IN employees.department_id%TYPE)
   IS
    CURSOR employee_cursors IS
    SELECT * FROM employees
	WHERE department_id = p_deptno;
     employee_record employee_cursors%ROWTYPE;

  BEGIN
     dbms_output.put_line('===================사원리스트================');

     FOR employee_record IN employee_cursors LOOP
	dbms_output.put_line(p_deptno ||'    '|| employee_record.employee_id
		||'     '|| employee_record.last_name);
     END LOOP;
 END;
/
--프로시저 실행
EXECUTE listByDeptno(50);

 

Q. 기존 jobs를 jobs2로 복사

    프로시저를 이용해서 job_id, job_title, min_salary, max_salary를 입력받아 jobs2테이블에 새로운 row를 추가

  CREATE TABLE jobs2 AS SELECT * FROM jobs;

  CREATE OR REPLACE PROCEDURE my_new_jobs_proc(
	p_job_id IN jobs2.job_id%TYPE,
	p_job_title IN jobs2.job_title%TYPE,
	p_min_salary IN jobs2.min_salary%TYPE,
	p_max_salary IN jobs2.max_salary%TYPE)
  IS

  BEGIN
	INSERT INTO jobs2(job_id, job_title, min_salary, max_salary)
	VALUES(p_job_id, p_job_title, p_min_salary, p_max_salary);

	COMMIT;
 END;
/
EXECUTE my_new_jobs_proc('a', 'a1', 1000, 5000);

 

Q. jobs2테이블의 job_id Column에 Primary Key 제약조건 추가

   프로시저를 이용하여 동일한 job_id를 체크

   (no : insert 실행, yes : 업데이트 실행)

  ALTER TABLE jobs2
	ADD CONSTRAINT job2_job_id_pk PRIMARY KEY(job_id)

 CREATE OR REPLACE PROCEDURE my_new_jobs_proc2(
	p_job_id IN jobs2.job_id%TYPE,
	p_job_title IN jobs2.job_title%TYPE,
	p_min_salary IN jobs2.min_salary%TYPE,
	p_max_salary IN jobs2.max_salary%TYPE)
 IS
    v_cnt NUMBER :=0;

 BEGIN
    --동일한 job_id 체크
    SELECT COUNT(*) INTO v_cnt
	FROM jobs2
	WHERE job_id = p_job_id;

    IF v_cnt = 0 THEN
        INSERT INTO jobs2(job_id, job_title, min_salary, max_salary)
	VALUES(p_job_id, p_job_title, p_min_salary, p_max_salary);
    ELSE
        UPDATE jobs2
	SET job_title = p_job_title,
  	     min_salary = p_min_salary,
	     max_salary = p_max_salary
	WHERE job_id = p_job_id;
    END IF;

    COMMIT;
END;
/
EXECUTE my_new_jobs_proc2('a', 'a100', 1300, 15000);
EXECUTE my_new_jobs_proc2('a1', 'a1', 100, 1000);

 

* 매개변수 DEFAULT 값 설정

CREATE OR REPLACE PROCEDURE my_new_jobs_proc3(
	p_job_id IN jobs2.job_id%TYPE,
	p_job_title IN jobs2.job_title%TYPE,
	p_min_salary IN jobs2.min_salary%TYPE := 100,
	p_max_salary IN jobs2.max_salary%TYPE := 10000)
 IS
    v_cnt NUMBER :=0;

 BEGIN
    --동일한 job_id 체크
    SELECT COUNT(*) INTO v_cnt
	FROM jobs2
	WHERE job_id = p_job_id;

    IF v_cnt = 0 THEN
        INSERT INTO jobs2(job_id, job_title, min_salary, max_salary)
	VALUES(p_job_id, p_job_title, p_min_salary, p_max_salary);
    ELSE
        UPDATE jobs2
	SET job_title = p_job_title,
  	     min_salary = p_min_salary,
	     max_salary = p_max_salary
	WHERE job_id = p_job_id;
    END IF;

    COMMIT;
END;
/
EXECUTE my_new_jobs_proc3('b2', 'b222');

 

* 매개변수 OUT, IN

   IN    : 외부에서 프로시저를 사용하기 위해 인자값을 입력할 때, 인자를 내부 변수에 할당

   OUT : 프로시저가 호출 및 종료 시 OUT이 명시된 변수를 외부로 반환

   INOUT : 위의 두가지 기능 모두 수행

CREATE OR REPLACE PROCEDURE my_new_jobs_proc4(
	p_job_id IN jobs2.job_id%TYPE,
	p_job_title IN jobs2.job_title%TYPE,
	p_min_salary IN jobs2.min_salary%TYPE := 100,
	p_max_salary IN jobs2.max_salary%TYPE := 10000,
	p_result OUT NUMBER)
 IS
    v_cnt NUMBER :=0;

 BEGIN
    --동일한 job_id 체크
    SELECT COUNT(*) INTO v_cnt
	FROM jobs2
	WHERE job_id = p_job_id;

    IF v_cnt = 0 THEN
        p_result := 1;
        INSERT INTO jobs2(job_id, job_title, min_salary, max_salary)
	VALUES(p_job_id, p_job_title, p_min_salary, p_max_salary);
    ELSE
        p_result := 2;	
        UPDATE jobs2
	SET job_title = p_job_title,
  	     min_salary = p_min_salary,
	     max_salary = p_max_salary
	WHERE job_id = p_job_id;
    END IF;

    COMMIT;
END;

 

프로시저 실행

DECLARE
  p_result NUMBER;
BEGIN
  my_new_jobs_proc4('c1', 'c11', 100, 1000, p_result);
  IF p_result = 1 THEN
     dbms_output.put_line('추가 되었습니다.');
  ELSE
     dbms_output.put_line('수정 되었습니다.');
  END IF;
END;

 

 

Q. hr) 사원번호를 입력받아 이름을 반환하는 함수를 구현 (사원이 없으면 사원이 없다고 출력)

CREATE OR REPLACE FUNCTION get_emp_name(
	p_employee_id employees.employee_id%TYPE)
RETURN VARCHAR2
IS
	result VARCHAR2(50) := null;
    
BEGIN
--사원명을 가져온다.
	SELECT last_name
	INTO result
	FROM employees
	WHERE employee_id = p_employee_id;

--사원명 반환
   RETURN result;

   EXCEPTION
      WHEN NO_DATA_FOUND THEN
          RETURN '해당 사원 없음';
END;
/   	

SELECT get_emp_name(100) FROM dual;

 

 

트리거(Trigger)

 - 특정 테이블의 데이터에 변경이 이루어 졌을 때 자동으로 다른 어떤 작업이 함께 수행되도록 설정하는 것

 

CREATE TABLE emp13(
    empno NUMBER PRIMARY KEY,
    ename VARCHAR2(20),
    job VARCHAR2(20)
 );

CREATE OR REPLACE TRIGGER trg_01
	AFTER INSERT
	ON emp13
	BEGIN
	   dbms_output.put_line('신입사원이 추가 되었습니다.');
END;
/
INSERT INTO emp13 VALUES(3, '홍길동', '개발');

 

 

트리거 유형

 - 문장레벨 트리거 - DML문을 실행할 때 한번만 트리거 실행


 - 행 레벨 트리거(FOR EACH ROW) - DML문 여러번 실행 => 트리거 여러번 수행

CREATE TABLE sal01(
   salno NUMBER PRIMARY KEY,
   sal NUMBER,
   empno NUMBER REFERENCES emp13(empno)
 )

 CREATE SEQUENCE sal01_salno_seq;

 CREATE OR REPLACE TRIGGER trg02
	AFTER INSERT
	ON emp13
	FOR EACH ROW
	BEGIN
	  INSERT INTO sal01 VALUES(sal01_salno_seq.NEXTVAL, 3000, :NEW.empno);
 END;


  - INSERT -> :OLD - NULL, :NEW -> 입력값
  - UPDATE -> :OLD ->변경전 값,  :NEW -> 변경후 값
  - DELETE -> :OLD -> 삭제전 값,  :NEW -> NULL


 INSERT INTO emp13 VALUES(2, '박길동', '개발');

 

 

Q.  사원이 삭제되면 그 사원의 급여 정보 (sal01) 테이블에서 해당 로우도 함께 삭제되도록 트리거를 구현

CREATE OR REPLACE TRIGGER trg_03
	AFTER DELETE
	ON emp13
	FOR EACH ROW
	BEGIN
	   DELETE FROM sal01 WHERE empno = :OLD.empno;
 	   dbms_output.put_line('급여정보에서도 삭제');
END;

 DELETE FROM emp13 WHERE empno = 2;

 

'kosta > [DB]Oracle' 카테고리의 다른 글

[DB] Data Modeling  (0) 2022.03.15
[Oracle] SQL문 정리 4  (1) 2022.03.11
[Oracle] SQL문 정리 3  (2) 2022.03.10
[Oracle] SQL문 정리 2  (1) 2022.03.09
[Oracle] SQL문 정리  (0) 2022.03.07

댓글