<서브쿼리를 이용한 DML문장>

 

  • 다량의 DML작업을 수행하는 경우 서브 쿼리문을 이용
  • IMSERT 작업에 대량 데이터를 입력할 시 서브쿼리를 이용하면 매우 효율적
  • 메모리를 통하지않고 데이터를 직접 디스크에 입력하는 다이렉트 로드를 같이 사용하면 효율성 배가

 

서브쿼리를 이용한 DML문
INSERT INTO [+APPEND] 테이블 [NOLOGGING]
[(컬럼, 컬럼, . . )]
SELECT 문장;


- 서브쿼리(SELECT문)에 검색된 행을 입력 값으로 사용한다.
- 한번에 많은 행을 입력할수있다.
- 컬럼리스트와 SELECT문의 컬럼이 1:1로 대응 되어야 한다.
- SELECT문에 사용한 서브 쿼리문과는 달리 괄호를 쓰지 않는다.
- [+ APPEND] : 다이렉트 로드함으로 대량의 입력작업을 더 빠르게 작업한다.
- [NOLOGGING] : 로그정보를 남기지 않음으로 입력작업이 빨라진다. 그러나 장애가 발생시 복구불가능

UPDATE 테이블
SET 컬럼명 = (SELECT 문장),
    컬럼명 = (SELECT 문장), ...
[WHERE 조건];

UPDATE 테이블
SET (컬럼, 컬럼, ...) = (SELECT 문장)
[WHERE 조건];

 

- UPDATE 문의 SET 절에는 단일 행 서브쿼리문이나 다중 열 서브 쿼리문을 이용할 수 있다.
- 다중열인 경우도 반드시 결과 행은 하나여야 한다.
- 이 때 검색되는 Data는 반드시 수정되는 컬럼명과 1:1 대응돼야 한다.
- SET 절에는 단일행 서브쿼리만 허용되지만 WHERE절의 서브 쿼리는 연산자에 따라 달라진다.

 

 

-- emp2 테이블에 사번과 연봉을 입력한다
 DESC emp2;
 SELECT * FROM emp2;
 
INSERT INTO emp2(eno, asal)
SELECT eno, sal*12+NVL(comm,0) FROM emp;
   
ROLLBACK;

 

-> 데이터 타입이 일치하지 않으면 에러 발생

 

-데이터 입력이 가능한 경우

1) 데이터 타입이 같고 저장 컬럼의 크기가 입력 데이터 크기보다 클 경우

2) 데이터 타입이 달라도 자동 형변환이 가능하고 저장 컬럼의 크기가 입력 데이터 크기보다 클 경우

- '10' => 10

 

--   숫자형 => 문자형 컬럼
INSERT INTO emp2(eno, asal)
SELECT eno, hdate FROM emp;

INSERT INTO emp2(eno, asal)
SELECT eno, ename FROM emp;


--아래 경우는 자동형변환 되어 들어간다
INSERT INTO emp2(eno, asal)
SELECT eno, dno FROM emp;
 
SELECT * FROM emp2; 


--각 사원의 정보와 근무지를 emp3 테이블에 저장하라
SELECT * FROM emp3;
DESC emp3;

 

 

 

 

 

 

<다이렉트 로드>

 

  • 일괄적인 대량의 DML 작업이 메모리에서 일어나면 비효율이 발생
  • 이를 피하기 위해 대량 DML 작업에서는 메모리를 통하지 않고 디스크에 직접 작업을 수행
  • ==>다이렉트 로드(Direct Load)
  • DML 작업을 다이렉트로드하기 위해서는 /*+ APPEND */를 문장에 삽입

 

/**/

: /*는 평소에는 주석으로 사용되지만 + 기호를 붙여줌으로써 주석이 아닌 오라클에 옵션을 전달하는 용도로 사용

 

- 오라클은 안전한 시스템 운영을 위해 장애 발생 시 복구할 수 있도록 DB에 변경을 가하는 모든 작업의 내용을

Redo Log영역에 로그 정보로 보관

 

- 대량의 DML작업은 작업 성능을 위해 로그 정보를 남기지 않고 NOLOGGING 옵션을 사용 -> 장애에 대비한 백업을 필요

==> 대량의 작업에서 다이렉트 로드와 NOLOGGING 방식을 사용하면 작업 성능은 비약적으로 향상되지만 작업의 안전도는 떨어지게 된다.

 

- 다이렉트 로드를 이용해서 대량의 데이터를 테이블에 입력한 경우 트랜잭션을 마무리 하지 않고 검색하게 되면 'ORA-12838: 병렬로 수정한 후 객체를 읽거나 수정할 수 없습니다'라는 에러를 만나게 된다.

==> COMMIT 을 수행한 이후 검색

 

--서브 쿼리를 이용한 UPDATE 문을 수행한다.

SELECT *
FROM emp
WHERE ename='윤고은';

--윤고은의 급여와 보너스를 각각 김연아의 급여와 손하늘의 보너스와 동일하게 수정한다
UPDATE emp
SET sal=(SELECT sal
         FROM emp
         WHERE ename='김연아'),
    comm = (SELECT comm
            FROM emp
            WHERE ename='손하늘')
WHERE ename='윤고은';

SELECT * FROM emp;



--제갈민과 동일한 부서의 사원들의 급여를
--제갈민의 급여와 동일하게 수정한다
SELECT * FROM emp
WHERE dno = (SELECT dno
            FROM emp
            WHERE ename = '제갈민');

UPDATE emp
SET sal=(SELECT sal
            FROM emp
            WHERE ename = '제갈민')
WHERE dno = (SELECT dno
            FROM emp
            WHERE ename = '제갈민');
            

--이초록의 급여, 보너스를 김연아와 동일하게 수정한다
UPDATE emp
SET (sal, comm) =(SELECT sal, comm
         FROM emp
         WHERE ename='김연아')
WHERE ename='이초록';


ROLLBACK;

 

 

 

 

 

<Exrecise>

--1. 일반 화학 과목을 수강하는 학생의 성적을 4.5만점 기준으로 수정한다
UPDATE student  SET avr = (avr/8*9)
WHERE sno IN(SELECT sno
                      FROM score
                      WHERE cno IN (SELECT cno
                                             FROM course
                                             WHERE cname='일반화학'));



--2. 화학과 교수의 과목중에 학점이 3학점 미만인 과목을 모두 3학점으로 수정한다
UPDATE course SET st_num = 3
WHERE st_num<3
AND pno IN(SELECT pno
                      FROM professor
                      WHERE section ='화학');



--3. 학생의 기말고사 성적을 모두 st_score 테이블에 저장한다
INSERT /*+ APPEND */  INTO st_score NOLOGGING
(sno, sname, major, syear, cno, cname, result)
SELECT student.sno, sname, major, syear, course.cno, cname, result
FROM student
JOIN score ON student.sno = score.sno
JOIN course ON score.cno=course.cno;

SELECT * FROM st_score;

COMMIT;

DELETE FROM st_score;



--4. st_score 테이블에 각 학생의 평점을 학과별, 과목별로 입력한다. 
--검색할 때 대부분 학과별 검색을 수행하기 때문에 이들 데이터가 학과별로 몰려있으면 성능을 향상시킬 수 있다

INSERT /*+ APPEND */  INTO st_score NOLOGGING
(sno, sname, major, syear, cno, cname, result)
SELECT student.sno, sname, major, syear, course.cno, cname, result
FROM student
JOIN score ON student.sno = score.sno
JOIN course ON score.cno = course.cno
ORDER BY major, cname;



--5. 화학과 학생이 수강하는 과목을 강의하는 교수의 부임일자를 1년 늦도록 수정한다.

UPDATE professor SET hiredate =(hiredate+365)
WHERE pno IN(SELECT pno
                      FROM course
                      WHERE cno IN (SELECT cno 
                                              FROM st_score
                                              WHERE major='화학'));

'db : sql' 카테고리의 다른 글

Oracle/ SELECT절 복습 adv  (0) 2020.02.28
Oracle/ SELECT절 복습  (0) 2020.02.28
Oracle/ DML(Data Manipulation Language)  (0) 2020.02.27
Oracle/ 서브쿼리 다중행 다중열  (0) 2020.02.27
Oracle/ 서브 쿼리 - 단일행 서브쿼리  (0) 2020.02.26