SQL - SELECT, INSERT, UPDATE 사용

    SELECT문의 사용

    기본 사용법

    DECLARE
    	v_cnt NUMBER;
    BEGIN
    	SELECT COUNT(*)
        	INTO v_cnt
       		FROM emp;
        DBMS_OUTPUT_PUT_LINE('COUNT(*) = ' || v_cnt);
    END;
        

    SELECT문의 특징은 쿼리를 실행하여 결과값을 가져오는 것이다.

    SELECT문이 실행되어 COUNT(*)의 결과가 계산되면 그 결과는 INTO 다음에 나타나는 PL/SQL 출력 변수인 v_cnt에 저장된다. SELECT절에 여러 개의 칼럼이 조회되는 경우는 밑의 코드와 같이 칼럼목록을 콤마로 분리하여 나열한다.

    SELECT되는 칼럼의 수와 동일한 개수의 출력 변수가 INTO절에 나열되는 것에 주의하라.

    DECLARE
        v_empno emp.empno%TYPE;
        v_ename emp.ename%TYPE;
        v_deptno emp.deptno%TYPE;
        v_job   emp.job%TYPE;
    BEGIN
        SELECT EMPNO, ENAME, DEPTNO, JOB
        INTO v_empno, v_ename, v_deptno, v_job  --출력 변수의 개수는 SELECT되는 칼럼의 수와 같다.
        FROM emp
        WHERE empno = 7788;
    END;

    배열 처리 시에는 INTO 앞에 BULK COLLECT를 추가하여 BULK COLLECT INTO 형태로 사용한다. 

     

    PL/SQL 입력 변수의 사용

    INTO절에는 SELECT문의 결과를 저장하는 출력변수만 사용할 수 있다.

    많은 경우에 SQL문의 실행 시 동적인 값을 입력으로 제공하기 위한 입력변수를 사용할 필요도 생긴다.

    또한 SELECT절의 칼럼에도 변수가 표현식으로 사용될 수 있다.

    -- SELECT문에서 PL/SQL 입력변수의 사용
    DECLARE
        v_empno emp.empno%TYPE;
        v_ename emp.ename%TYPE;
        v_rate number := 1.1;
        v_sal number;
    BEGIN
        v_empno := 7788;
        SELECT ename
            , (sal+comm)*v_rate -- SELECT 칼럼에 입력변수 v_rate 사용
            INTO v_ename, v_sal -- 출력변수
            FROM emp
        WHERE empno = v_empno;  -- 리터럴을 입력변수 v_empno로 대체
    END;

    %ROWTYPE을 사용하면 변수선언과 INTO절을 훨씬 간단하게 할 수 있다.

    -- SELECT문에서 %ROWTYPE의 사용
    DECLARE
        v_emprec emp%ROWTYPE;   -- 레코드 변수 선언
    BEGIN    
        v_emprec.empno := 7788;
        SELECT *
            INTO v_emprec   -- 레코드 변수 사용
            FROM emp
        WHERE empno = v_emprec.empno;
        DBMS.OUTPUT_PUT_LINE('이름 : ' ||v_emprec.ename);
        DBMS.OUTPUT_PUT_LINE('부서번호 : ' ||v_emprec.deptno);
    END;
    	

    SELECT문의 결과는 항상 INTO절에 지정된 변수에 저장된다.

    SELECT절에 변수를 지정하면 SELECT 결과가 그 변수에 저장되는 것이 아니라 변수가 가진 값이 INTO절에 지정된 변수로 반환된다.

    --SELECT절에 변수를 사용하면 결과를 변수에 저장하는 게 아니라 변수의 값을 반환한다
    SCOTT> SELECT ename
    		FROM emp
           WHERE empno = 7788;
           
    ENAME
    -------------
    SCOTT
    
    SCOTT> DECLARE
    		v_name	emp.ename%TYPE;
            v_ename emp.ename%TYPE;
          BEGIN
          	v_name := 'TIGER';
            SELECT v_name
            INTO  v_ename
            FROM emp
           WHERE empno = 7788;
           DBMS_OUTPUT_PUT_LINE('이름: '||v_ename);
     	END;;
    	/
        

    위 코드는 SELECT문에 변수 v_name을 사용하면 사번 7788의 이름인 SCOTT이 변수 v_name에 저장되는 게 아니라 변수 v_name에 저장된 값인 'TIGER'가 INTO절의 변수 v_ename에 저장되는 것을 보여준다.

     

    INSERT문의 사용

    INSERT문은 지정된 값을 테이블에 삽입하고 결과행을 반환하지 않는 SQL문이다.

    -- 가장 간단한 INSERT문
    BEGIN
    	INSERT INTO emp(empno, ename, hiredate, deptno)
        VALUES			(9000, '홍길동', SYSDATE, 30);
        DBMS_OUTPUT_PUT_LINE('INSERT 건수: '||SQL%ROWCOUNT); --변경된 건수 출력
        COMMIT;
    END;

    INSERT문에서도 SELECT문과 마찬가지로 PL/SQL 변수를 사용할 수 있다.

    --INSERT문에서 PL/SQL 입력변수 사용
    REM 앞에서 삽입한 로우 삭제
    DELETE FROM emp WHERE empno = 9000;
    
    DECLARE
    	v_empno emp.empno%TYPE;
        v_ename emp.ename%TYPE;
        v_deptno emp.deptno%TYPE;
    BEGIN
    	v_empno := 9000;
        v_ename := '홍길동';
        v_deptno := 30;
        
        INSERT INTO emp(empno, ename, hiredate, deptno)
        VALUES			(v_empno, v_ename, SYSDATE, v_deptno);	-- PL/SQL 변수 사용
        DBMS_OUTPUT_PUT_LINE('INSERT 건수: ' ||SQL%ROWCOUNT);	-- 변경된 건수 출력
        COMMIT;
    END;

    INSERT문도 %ROWTYPE을 사용하여 레코드변수를 선언하면 프로그램을 훨씬 간단하게 작성할 수 있다.

    --INSERT문에서 %ROWTYPE의 사용
    REM 앞에서 삽입한 로우 삭제
    DELETE FROM emp WHERE empno = 9000;
    
    DECLARE
    	v_emprec emp%ROWTYPE;	-- 레코드 변수 선언
    BEGIN
    	v_emprec.empno		:= 9000;
        v_emprec.ename		:= '홍길동';
        v_emprec.deptno		:= 30;
        v_emprec.hiredate	:= SYSDATE;
        
        INSERT INTO emp
        VALUES		v_emprec;
        DBMS_OUTPUT.PUT_LINE('INSERT 건수: '||SQL%ROWCOUNT); -- 변경된 건수 출력
        COMMIT;
     END;

    예제 스키마 계정 scott의 테이블 emp는 모두 여덟 개의 컬럼을 가지고 있기 때문에 위 코드의 레코드 변수 v_emp도 여덟 개의 필드를 가졌다. 위 코드에서는 그 중 네 개의 필드만 값을 지정했다. 값을 지정하지 않은 나머지 네 개의 필드는 값이 NULL이다. 따라서 INSERT할 떼 이에 대응되는 네 개의 칼럼에는 NULL이 저장된다.

     

    INSERT문에서 테이블명이나 INSERT 대상으로 나열되는 컬럼명은 변수로 사용할 수 없다.

    정적SQL은 컴파일 시에 문법과 의미검사를 수행하는데 테이블명이나 칼럼명에 변수를 허용하면 문법검사와 의미검사 모두 불가능해지므로 이를 허용하는 것은 PL/SQL 언어의 기본 철학에 위배된다.

     

    INSERT문에 배열 처리를 사용하기 위해서는 FORALL문을 사용해야한다. FORALL은 다음에 알아본다.

     

    UPDATE문 사용

    INSERT문과 마찬가지로 지정된 값을 사용하여 테이블의 로우를 변경하고 결과 행을 반환하지 않는 SQL문.

    -- 가장 간단한 UPDATE문
    BEGIN
    	UPDATE emp
        SET	deptno = 40
        WHERE empno = 9000;
        DBMS_OUTPUT_PUT_LINE('UPDATE 건수: '||SQL%ROWCOUNT); -- 변경된 건수 출력
        COMMIT;
    END;

    UPDATE문도 PL/SQL 변수 사용 가능하다.

    DECLARE
    	v_empno	emp.empno%TYPE := 9000;
        v_deptno emp.deptno%TYPE := 40;
    BEGIN
    	UPDATE emp
        SET deptno = v_deptno -- 입력변수
        WHERE empno = v_empno -- 입력변수
        DBMS_OUTPUT_PUT_LINE('UPDATE 건수: ' ||SQL%ROWCOUNT); --변경된 건수 출력
        COMMIT;
    END;
    --UPDATE문에서 %ROWTYPE 사용
    DECLARE
    	v_emprec	emp%ROWTYPE;	-- 레코드변수 선언
    BEGIN
    	v_emprec.empno := 9000;
        
        -- 원래의 값을 조회
        SELECT * 
        INTO v_emprec
        FROM emp
        WHERE empno = v_emprec.empno;
        
        --이름과 부서번호 필드값을 변경
        v_emprec.ename := '홍길동';
        v_emprec.deptno := 40;
        
        --변경된 값을 테이블에 반영
        UPDATE emp
        SET ROW = v_emprec	-- 레코드 변수를 사용한 UPDATE
        WHERE empno = v_emprec.empno;
        COMMIT;
    END;

    INSERT문에서 설명한 것과 동일한 이유로 레코드 변수읭 특정필드에만 값을 지정하고 UPDATE문을 수행하면 값을 지정하지 않은 필드에 해당하는 컬럼의 값은 NULL이 된다. 이렇게 하면 의도치 않은 컬럼의 값이 NULL로 변경될 수 있으므로 위 프로그램과 같이 먼저 모든 컬럼의 값을 SELECT한 후 특정 컬럼만 변경하는 것이 좋다.

     

    UPDATE문에서 레코드변수는 18번 줄과 같이 SET ROW 다음에만 사용할 수 있으며, 레코드변수는 단 한 개만 사용할 수 있다. UPDATE문도 역시 키워드(UPDATE, SET, ROW, WHERE 등)나 테이블명, SET의 대상이 되는 컬럼명에는 변수를 사용할 수 없다. UPDATE문에서 배열 처리를 사용하기 위해서는 INSERT문처럼 FORALL문을 사용해야 한다.

    'DATABASE > SQL, PL-SQL' 카테고리의 다른 글

    트랜잭션(Transaction) 제어  (0) 2021.01.27
    SQL - MERGE, DELETE문의 사용  (0) 2021.01.25
    표현식 - 2  (0) 2021.01.24
    표현식 - 1  (0) 2021.01.24
    변수와 상수, 리터럴  (0) 2021.01.20

    댓글