081 COMMIT, ROLLBACK
COMMIT
: COMMIT 이전에 수행했던 DML 작업들을 데이터베이스에 영구히 반영하는 TCL이다.
ROLLBACK
: 마지막 COMMIT 명령어를 수행한 이후DML문을 취소
하는TCL
- SCOTT의 월급을 4000으로 변경한 UPDATE문이 취소된다.
SELECT * FROM EMP;
INSERT INTO EMP(empno, ename, sal, deptno) VALUES(1123, 'JANE', 2500, 21);
COMMIT;
-> 커밋 완료SELECT * FROM EMP;
UPDATE EMP SET SAL = 4000 WHERE ENAME ='JANE';
SELECT * FROM EMP WHERE ENAME = 'JANE';
ROLLBACK;
SELECT * FROM EMP WHERE ENAME = 'JANE';
종류 | 설명 |
---|---|
COMMIT | 모든 변경사항을 데이터베이스에 반영 |
ROLLBACK | 모든 변경사항을 취소 |
SAVEPOINT | 특정 지점까지의 변경을 취소 |
082 데이터 입력, 수정, 삭제 한 번에 하기 (MERGE)
---082
ALTER TABLE emp
ADD loc varchar2(10); --- 사원 테이블에 부서 위치 컬럼 추가
MERGE INTO emp e --MERGE 대상이 되는 TARGET 테이블명 작성
USING dept d --- SOURCE 테이블명. DEPT로부터 데이터를 읽어와,
DEPT 테이블의 데이터로 EMP 테이블을 MERGE한다.
ON (e.deptno = d.deptno) --- TARGET 과 SOURCE 테이블을 조인하는 구문.
--- 조인에 성공하면 MERGE UPDATE절 실행,
실패하면 MERGE INSERT절 실행
WHEN MATCHED THEN -- MERGE UPDATE절
UPDATE set e.loc = d.loc
WHEN NOT MATCHED THEN -- MERGE INSERT절
INSERT (e.empno, e.deptno, e.loc) VALUES (1111,d.deptno, d.loc) ;
--- 부서 테이블을 이용해 해당 사원의 부서 위치로 값이 갱신되도록 함
--- 만약 부서 테이블에는 존재하는 부서이지만 사원 테이블에 없는 부서번호라면, 새롭게 사원 테이블로 입력
083 락(lock) 이해하기
sqlplus를 연다
창 두개를 띄워서 로그인 해둔다.
터미널 1
SQL> UPDATE emp
2 SET sal = 3000
3 WHERE ename='JONES';
1 row updated.
UPDATE를 실행하게 되면 행 전체를 잠그기 때문에, JONES의 월급 뿐만 아니라 다른 컬럼들의 데이터도 변경할 수 없고 WAITING하게 된다.
- 터미널 2
SQL> UPDATE emp
2 SET sal = 9000
3 WHERE ename='JONES';
커서 깜박이기만 함
UPDATE문을 수행하면, UPDATE 대상이 되는 행(ROW)을 잠궈(LOCK)버린다.
- 터미널 창 1에 접속한 세션이 JONES의 행을 갱신하고,
아직 COMMIT이나 롤백을 수행하지 않았기 때문에 해당 행이 잠겨 있기 때문이다.
SQL> COMMIT;
Commit complete.
COMMIT을 수행하게 되면, UPDATE가 실행되고 행에 걸렸던 잠금은 해제된다.
SQL>
SQL> UPDATE emp
2 SET sal = 9000
3 WHERE ename='JONES';
1 row updated.
터미널1의 행에 걸린 잠금을 해제하였기 때문에, 터미널 창2는 수정이 바로 된다.
데이터의 일관성을 보장
터미널 창1은 자기가 변경한 데이터를 커밋하기 전까지 일관되게 유지해야 한다.
커밋하기 전까지는 자기가 변경한 데이터에 대해 일관성이 보장되어야 한다.
그래서 오라클에서는 LOCK을 사용하여 UPDATE문을 수행하면 해당 행에 LOCK을 건다.
084 SELECT FOR UPDATE절 이해하기
터미널창 1
JONES의 데이터를 검색하는데, 행에 자동으로 락이 걸린다.
터미널창 2
UPDATE 변경이 안되고, WAITING하게 된다.
터미널창 1
COMMIT을 수행
터미널창 2
터미널창1에서 COMMIT을 하게 되면, 터미널창 2에서 UPDATE문이 수행된다.
085 서브쿼리를 사용하여 데이터 입력하기
CREATE TABLE emp2
as
SELECT *
FROM emp
WHERE 1=2;
INSERT INTO emp2(empno, ename, sal, deptno)
SELECT empno, ename, sal, deptno ---VALUES 대신 입력하고자 하는 서브 쿼리문을 기술.
INSERT문의 컬럼 순서와 맞춘다.
FROM emp
WHERE deptno = 10;
086 서브 쿼리를 사용하여 데이터 수정하기
-- 086
UPDATE EMP
SET SAL = (SELECT SAL
FROM EMP
WHERE ENAME ='ALLEN')
WHERE JOB = 'SALESMAN';
UPDATE문 | 서브 쿼리 가능 여부 |
---|---|
UPDATE절 | 서브 쿼리 사용 가능 |
SET절 | 서브 쿼리 사용 가능 |
WHERE절 | 서브 쿼리 사용 가능 |
087 서브쿼리를 사용하여 데이터 삭제하기
--- 087
DELETE FROM EMP
WHERE SAL > (SELECT SAL
FROM EMP
WHERE ENAME='SCOTT');
SELECT * FROM EMP;
088 서브쿼리를 사용하여 데이터 합치기
--- 088 서브쿼리를 사용하여 데이터 합치기
alter table dept
add sumsal number(10);
--- 사원 테이블을 이용하여 SUMSAL 컬럼의 데이터를 부서 테이블의 부서 번호별 토탈 월급으로 갱신
MERGE INTO dept d
USING (SELECT deptno, sum(sal) sumsal
FROM emp
GROUP BY deptno) v
ON (d.deptno = v.deptno)
WHEN MATCHED THEN
UPDATE set d.sumsal = v.sumsal;
093 일반 테이블 생성하기
- 반드시 문자로 시작
- 이름의 길이는 30자 이하여야 한다.
- 대문자 알파벳과 소문자 알파벳과 숫자를 포함할 수 있다.
- 특수문자는 $, _, #만 포함할 수 있다.
유형 | 설명 |
---|---|
CHAR | 고정 길이 문자 데이터 유형, 최대 길이는 2000 |
VARCHAR2 | 가변 길이 문자 데이터 유형, 최대 길이 4000 |
LONG | 가변 길이 문자 데이터 유형, 최대 2GB의 문자 데이터를 허용한다. |
CLOB | 문자 데이터 유형, 최대 4GB의 문자 데이터를 허용 |
BLOB | 바이너리 데이터 유형, 최대 4GB 바이너리 데이터를 허용 |
NUMBER | 숫자 데이터 유형, 십진 숫자의 자리수는 최대 38자리까지 허용 가능, 소숫점 이하 자리는 -84 ~127까지 허용한다. |
DATE | 날짜 데이터 유형, 기원전 4712년 01월 01일부터 기원후 9999년 12월 31일까지의 날짜를 허용 |
--- 094 임시 테이블 생성하기 CREATE TEMPORARY TABLE
옵션 | 설명 |
---|---|
ON COMMIT DELETE ROWS | 임시 테이블에 데이터를 입력하고, COMMIT 할 때까지만 데이터를 보관 |
ON COMMIT PRESERVE ROWS | 임시 테이블에 데이터를 입력하고 세션이 종료될 때까지 데이터를 보관 |
095 복잡한 쿼리를 단순하게 하기
---095
CREATE VIEW EMP_VIEW --- VIEW이름
AS --- VIEW를 통해 보여줘야할 쿼리를 작성
SELECT EMPNO, ENAME, SAL, JOB, DEPTNO
FROM EMP
WHERE JOB ='SALESMAN';
VIEW는 데이터를 가지고 있지 않고, 단순히 테이블을 바로 보는 객체이다.
VIEW를 쿼리하면, 뷰를 만들 때 작성했던 쿼리문이 수행되면서, 실제 EMP 테이블을 쿼리한다.
UPDATE문도 마찬가지로, EMP_VIEW를 갱신하면 실제 테이블인 EMP의 데이터가 갱신된다.
096 복잡한 쿼리 단순하게 하기
단순 VIEW | 복합 VIEW | |
---|---|---|
테이블의 개수 | 1개 | 2개 이상 |
함수 포함 여부 | 포함 안 함 | 포함 |
데이터 수정 여부 | 수정 가능 | 수정 불가능 할 수 있음 |
복합 VIEW
- 그룹 함수를 쿼리하는 복합 뷰는 수정이 되지 않는다.
- 큰 장점은 바로 복잡한 쿼리를 단순화 시킬 수 있다는 점.
097 데이터 검색 속도 높이기 INDEX
--097 INDEX
CREATE INDEX EMP_SAL
ON EMP(SAL); -- 인덱스를 생성하고자 하는 테이블과 컬럼명
-- 세션창이 하나만 있어야 쿼리문 실행 가능
SELECT ENAME, SAL
FROM EMP
WHERE SAL = 1600;
인덱스가 없을 때는 테이블을 FULL SCAN한다.
인덱스는 컬럼값과 ROWID로 구성된다.
ROWID : 데이터가 있는 행의 물리적 주소
컬럼값은 내림차순으로 정렬.
① 인덱스가 월급을 내림차 순으로 정렬하고 있으므로, 바로 월급 1600을 찾는다.
② 인덱스의 ROWID로 테이블의 해당 ROWID 찾아 이름과 월급을 조회한다.
- 검색할 데이터만 바로 스캔
098
-- 098 절대로 중복되지 않는 번호 만들기
CREATE SEQUENCE SEQ1
START WITH 1
INCREMENT BY 1
MAXVALUE 100
NOCYCLE;
SELECT MAX(EMPNO) FROM EMP;
INSERT INTO EMP(EMPNO, ENAME, SAL, JOB, DEPTNO)
VALUES (8300, 'JAMES', 3500, 'ANALYST', 23);
CREATE TABLE EMP02
( EMPNO NUMBER(10),
ENAME VARCHAR2(10),
SAL NUMBER(10) );
INSERT INTO EMP02 VALUES( SEQ1.NEXTVAL, 'JACKK', 3500);
INSERT INTO EMP02 VALUES( SEQ1.NEXTVAL, 'JAMESS', 4500);
SELECT *
FROM emp02;
SEQ1.NEXTVAL
시퀀스이름.NEXTVAL
사용한다. 099 실수로 지운 데이터 복구하기
SELECT SYSTIMESTAMP FROM DUAL;
SELECT SYSTIMESTAMP - INTERVAL '5' MINUTE FROM DUAL; --현재 시간에서 5분을 뺀 시간
100 실수로 지운 데이터 복구하기 FLASHBACK TABLE
--- 100 실수로 데이터를 delete 하고 commit 하였을 경우 복구 방법을 학습한다.
ALTER TABLE EMP ENABLE ROW MOVEMENT; --플래쉬백이 가능한 상태로 설정
FLASHBACK TABLE EMP TO TIMESTAMP(SYSTIMESTAMP - INTERVAL '5' MINUTE);
-- 플래쉬백은 백업을 가지고 복구하는 것이 아니라, 5분 전부터 현재까지 수행했던 DML 작업을 반대로 수행하면서 과거로 되돌린다.
---플래쉬백 확인
SELECT ROW_MOVEMENT
FROM user_tables WHERE table_name = 'EMP';
---
SELECT *
FROM emp
WHERE ename='KING';
5분 전부터 현재까지 수행한 작업 중 DELETE가 있었다면, 반대로 INSERT를 수행하고 INSERT가 있었다면, 반대로 DELETE를 수행한다.
성공적으로 플래쉬백이 되었다면 데이터를 확인한 후, COMMIT을 해야 변경된 상태가 데이터베이스에 영구히 반영된다.
👉 지정된 과거 시점부터 현재 시점 사이에 DDL(Data Definition Language)문이나, DCL(Data Control Langage)문을 수행하였다면 FLASHBACK명령어가 수행되지 않고 에러가 발생하게 된다.
101 FLASHBACK DROP
--- 101 FLASHBACK DROP
DROP TABLE EMP;
-- DROP 후 휴지통에 존재하는지 확인하는 방법
SELECT original_name, droptime
FROM user_recyclebin;
FLASHBACK TABLE EMP TO BEFORE DROP;
--- 휴지통에서 복구할 때 테이블명을 다른 이름으로 변경하려면 다음과 같이 수행
FLASHBACK TABLE EMP TO BEFORE DROP RENAME TO EMP2;
102 실수로 지운 데이터 복구하기 FLASHBACK VERSION QUERY
--- 102
SELECT SYSTIMESTAMP FROM DUAL;
SELECT ename, sal, deptno
FROM emp
WHERE ename='KING';
UPDATE emp
SET sal = 8000
WHERE ename='KING';
COMMIT;
UPDATE emp
SET deptno = 20
WHERE ename='KING';
COMMIT;
--- alter table EMP enable row movement ;
--- KIN의 데이터 변경 이력 정보를 확인한다.
SELECT ename, sal, deptno, versions_starttime, versions_endtime, versions_operation
FROM emp
VERSIONS BETWEEN TIMESTAMP TO_TIMESTAMP('2023/04/08 22:47:40','RRRR-MM-DD HH24:MI:SS')
AND MAXVALUE
WHERE ename='KING'
ORDER BY versions_starttime;
-- 쿼리의 날짜와 시간은 앞에서 미리 확인한 날짜와 시간으로 작성하여 수행하여야 한다.
103 FLASHBACK TRANSACTION QUERY
특정 테이블을 과거의 특정 시점으로 되돌리기 위한 DML문을 추출하는 방법을 학습
사원 테이블의 데이터를 5분 전으로 되돌리기 위한 DML문을 출력
SQL PLUS에서 작업
DB를 정상 종료한다. SHUTDOWN IMMEDIATE;
데이터베이스를 마운트 상태로 올린다.
STARTUP MOUNT
TRANSACTION QUERY 결과를 보기 위해서는 데이터베이스 모드를 아카이브 모드로 변경해야 한다.
아카이브 모드로 변경하겠다는 것은 장애가 발생하였을 때 DB를 복구할 수 있는 로그 정보를 자동으로 저장하게 하는 모드
👉 아카이브 모드로 변경하기 위해서는 DB를 한 번 내렸다 올려야 한다.
❌ - 시도했다가 번거로워서 진행 중단하기로 했다.
104 primary key 생성
105 데이터의 품질 높이기 unique
--- null값을 입력할 수 있다.
DNAME VARCHAR2(14) CONSTRAINT DEPT3_DNAME_UN UNIQUE,
CREATE TABLE DEPT4
( DEPTNO NUMBER(10),
DNAME VARCHAR2(13),
LOC VARCHAR2(10) );
ALTER TABLE DEPT4
ADD CONSTRAINT DEPT4_DNAME_UN UNIQUE(DNAME);
107 CHECK
--- 107 CHECK
CREATE TABLE EMP6
( EMPNO NUMBER(10),
ENAME VARCHAR(20),
SAL NUMBER(10) CONSTRAINT EMP6_SAL_CK
CHECK (SAL BETWEEN 0 AND 6000)
);
INSERT INTO emp6 VALUES (7839, 'KING', 5000);
INSERT INTO emp6 VALUES (7698, 'BLAKE', 2850);
INSERT INTO emp6 VALUES (7782, 'CLARK', 2450);
INSERT INTO emp6 VALUES (7839, 'JONES', 2975);
COMMIT;
SELECT * FROM emp6;
108 FOREIGN KEY
- EMP7 테이블의 DEPTNO가 DEPT7 테이블의 DEPTNO를 참조하고 있어서,
- EMP7 테이블의 DEPTNO에 데이터를 입력 또는 수정 시
- DEPT7 테이블의 DEPTNO에 존재하는 부서 번호에 대해서만 입력 또는 수정이 가능하게 된다.
ALTER TABLE DEPT7
DROP CONSTRAINT DEPT7_DEPTNO_PK CASCADE;
109 WITH절 사용하기
--- 109 WITH절 사용하기
-- 동일한 SQL이 반복되어 사용될 때 성능을 높이는 방법
-- 직업과 직업별 토탈 월급을 출력하는데 직업별 토탈 월급들의 평균값보다 더 큰 값들만 출력
WITH JOB_SUMSAL AS ( SELECT JOB, SUM(SAL) as 토탈
FROM EMP
GROUP BY JOB )
SELECT JOB, 토탈
FROM JOB_SUMSAL
WHERE 토탈 > ( SELECT AVG(토탈)
FROM JOB_SUMSAL );
직업과 직업별 토탈 월급을 출력하여 임시 저장 영역(Temporary Tablespace)에 테이블명을 job_sumsal로 명명지어 저장한다.
임시 저장 영역에 저장된 테이블인 job_sumsal을 불러와서 직업별 토탈 월급들의 평균값보다 더 큰 직업별 토탈 월급들을 출력
임시 저장 영역에 저장된 데이터를 출력하는데 많은 시간이 걸렸다면, with절은 이 시간을 반으로 줄여준다.
위의 with 절을 서브쿼리문으로 수행하면 다음과 같다.
SELECT JOB, 토탈
FROM JOB_SUMSAL
WHERE 토탈 > ( SELECT AVG(토탈)
FROM JOB_SUMSAL );
이는 동일한 sql을 두 번이나 사용하여 2배는 걸리게 된다. 그러나 with절로 고쳐 작성하게 되면, 5개의 데이터를 임시 저장 영역에 저장하고, 그 데이터를 job_sumsal 테이블 이름으로 불러오기만 하면 되기 때문에 시간이 절반으로 줄어든다.
🚨 단, with절에서 사용한 temp 테이블은 with절 내에서만 사용 가능하다.
110 SUBQUERY FACTORING
WITH JOB_SUMSAL AS ( SELECT JOB, SUM(SAL) 토탈
FROM EMP
GROUP BY JOB ) ,
-- 직업과 직업별 토탈 월급을 출력하여 JOB_SUMSAL이라는 이름으로 임시 저장 영역에 저장한다.
DEPTNO_SUMSAL AS ( SELECT DEPTNO, SUM(SAL) 토탈
FROM EMP
GROUP BY DEPTNO
HAVING SUM(SAL) > ( SELECT AVG(토탈) + 3000
FROM JOB_SUMSAL )
)
-- 부서번호와 부서 번호별 토탈 월급을 출력하는데
--- JOB_SUMSAL의 토탈값의 평균에 3000을 더한 값보다 더 큰 토탈 월급을 출력.
-- 여기서 JOB_SUMSAL 임시 테이블을 참조하고 있다. 이러한 방법은 FROM절의 서브쿼리로는 불가능하다.
SELECT DEPTNO, 토탈
FROM DEPTNO_SUMSAL ;