클라우드 융합 Full-stack 웹 개발자 양성과정/SQL, JDBC

SQL활용 - DDL(복합키, FOREIGN KEY 제약조건, 테이블 복사, ALTER, DROP), DML(INSERT, UPDATE, DELETE), DCL(GRANT, REVOKE, SAMPLE계정), TCL(COMMIT, ROLLBACK, SAVEPOINT)

thesunset 2022. 10. 4. 22:59

④-1  DDL_복합키

- 두 컬럼을 하나로 묶어서 PRIMARY KEY 하나로 설정이 가능하다. 

EX) 쇼핑몰 속 찜하기는 하나의 고객은 여러개의 상품을 찜할 수도 있기에 'USER'+'상품' 두개의 컬럼값을 하나의 PRIMARY KEY로 만들 수 있음 => '복합키'

CREATE TABLE MEM_PRIMARYKEY2(
 MEM_NO NUMBER,
 MEM_ID VARCHAR2(20),
 MEM_PWD VARCHAR2(20) NOT NULL,
 MEM_NAME VARCHAR2(20) NOT NULL,
 GENDER CHAR(3) CHECK(GENDER IN ('남', '여')),
 PHONE VARCHAR2(15),
 EMAIL VARCHAR2(30),
 PRIMARY KEY(MEM_NO, MEM_ID) --컬럼을 묶어서 RPIMARY KEY 하나로 설정
);

INSERT INTO MEM_PRIMARYKEY2 
VALUES(1, 'USER01', 'PASS01', 'HONG', NULL, NULL, NULL);

 SELECT * FROM MEM_PRIMARYKEY2;

INSERT INTO MEM_PRIMARYKEY2 
VALUES(2, 'USER01', 'PASS02', 'HONG', NULL, NULL, NULL);
--> MEM_NO과 MEM_ID 중 하나만 달라도 정상적으로 삽입 가능

INSERT INTO MEM_PRIMARYKEY2
VALUES(NULL, 'USER02', 'PASS03', 'KIM', NULL, NULL, NULL);
--> 기본키로 설정되어있는 컬럼들에는 NULL값이 들어갈 수 없음

- 회원 등급에 대한 데이터(등급코드, 등급명)를 보관하는 테이블

- MEM_GRADE ->테이블명
- GRADE_CODE -> 컬렴명, CHAR(2)형, 기본키
- GRADE_NAME -> 컬럼명, VARCHAR2(20), NULL값 불가

CREATE TABLE MEM_GRADE(
    GRADE_CODE CHAR(2) PRIMARY KEY,
    GRADE_NAME VARCHAR2(20) NOT NULL
);

INSERT INTO MEM_GRADE 
VALUES ('G1', '일반회원');

INSERT INTO MEM_GRADE
VALUES ('G2', '우수회원');

INSERT INTO MEM_GRADE
VALUES ('G3', '특별회원');

SELECT * FROM MEM_GRADE;

 ⑤ FOREIGN KEY(외래키) 제약조건

: 해당 컬럼에 다른 테이블 존재하는 값만 들어와야 될 때 부여하는 제약조건
    => 다른테이블(부모테이블)을 참조한다고 표현 

 

즉, 참조된 다른 테이블이 제공하고 있는 값만 들어올 수 있다. 
    => FOREIGN KEY제약조건으로 다른 테이블간의 관계를 형성할 수 있음

 

    - 컬럼레벨방식
    컬럼명 자료형 REFEREBCES 참조할테이블명(참조할 컬럼명)
    
    - 테이블레벨방식
    FOREIGN KEY(컬럼명) REFERENCES 참조할 테이블명(참조할 컬럼명)
    
    두 방식 모두 참조할 컬럼명은 생략 가능
    생략 시 기본적으로 참조할 테이블의 PRIMARY KEY컬럼으로 참조할 컬럼명으로 잡힘

 

-자식테이블 생성

CREATE TABLE MEM(
    MEM_NO NUMBER PRIMARY KEY,
    MEM_ID VARCHAR2(20) NOT NULL UNIQUE,
    MEM_PWD VARCHAR2(20) NOT NULL,
    MEM_NAME VARCHAR2(20) NOT NULL,
    GRADE_ID CHAR(2) REFERENCES MEM_GRADE(GRADE_CODE),
    GENDER CHAR(3) CHECK(GENDER IN('남', '여')),
    PHONE VARCHAR2(15),
    EMAIL VARCHAR2(30)

);

SELECT * FROM MEM;

INSERT INTO MEM
VALUES (1, 'USER01', 'PASS01', '홍길동', 'G1', NULL, NULL, NULL);

INSERT INTO MEM
VALUES (2, 'USER02', 'PASS02', '김길동', 'G2', NULL, NULL, NULL);

INSERT INTO MEM
VALUES (3, 'USER03', 'PASS03', '김말동', 'G1', NULL, NULL, NULL);

SELECT MEM_ID, MEM_PWD, MEM_NAME, GRADE_NAME
FROM MEM, MEM_GRADE
WHERE GRADE_ID = GRADE_CODE;
INSERT INTO MEM
VALUES (4, 'USER04', 'PASS04', '김동동', NULL, NULL, NULL, NULL);

INSERT INTO MEM
VALUES (5, 'USER05', 'PASS05', '김당당', 'G4', NULL, NULL, NULL);
-->ORA-02291: integrity constraint (DDL.SYS_C007105) violated - parent key not found 컬럼의 조건에 맞지 않는 값을 입력해 무결성제약조건에 위배됨
-- PARENT KEY NO FOUND발생
-- G4등급은 MEM_GRADE 테이블의 GRADE_CODE컬럼에서 제공하는 값이 아니기 때문에 오류발생

- 만약, 부모테이블(EME_GRADE)에서 데이터값이 삭제된다면?

: MEM_GRADE 테이블로부터 GRADE_CODE G1인 데이터 지우기

DELETE FROM MEM_GRADE
WHERE GRADE_CODE = 'G1';

-> 자식테이블(MEM)중에 G1을 사용하고 있기 때문에 삭제할 수 없음

-외래키 제약조건 부여 시 삭제 옵션을 부여하지 않았음
-자식테이블에서 사용하고 있는 값이 있을 경우 삭제가 안되는 "삭제제한옵션"이 걸려있음

 

DELETE FROM MEM_GRADE
WHERE GRADE_CODE = 'G3';

-> 자식테이블에서 사용되고 있는 값이 아니기 때문에 삭제 가능

 

SELECT * FROM MEM_GRADE;

-> 행이 삭제됨

ROLLBACK;

--DROP TABLE MEM; --구조를 삭제
--DELETE FROM MEM_GRADE; --데이터를 삭제

* 자식테이블 생성 시 (외래키 제약조건 부여 시)
  부모테이블의 데이터가 삭제되었을 때 자식테이블에서는 어떻게 처리할 건지 옵션으로 정할 수 있음

# FOREGIN KEY 삭제옵션
   삭제옵션을 별도로 지정하지 않으면 기본적으로 ON DELETE RESTRICTED(삭제제한)으로 설정

 

1) ON DELETE SET NULL : 부모데이터 삭제 시 해당 데이터를 사용하고 있는 자식데이터를 NULL로 변경시키겠다.

- 테이블 생성

CREATE TABLE MEM(
MEM_NO NUMBER PRIMARY KEY,
MEM_ID VARCHAR2(20) NOT NULL UNIQUE,
MEM_PWD VARCHAR2(20) NOT NULL,
MEM_NAME VARCHAR2(20) NOT NULL,
GRADE_ID CHAR(2), 
GENDER CHAR(3) CHECK(GENDER IN('남', '여')),
PHONE VARCHAR2(15), 
EMAIL VARCHAR2(30),
FOREIGN KEY(GRADE_ID) REFERENCES MEM_GRADE(GRADE_CODE) ON DELETE SET NULL
);

- 데이터 입력 

INSERT INTO MEM
VALUES (1, 'USER01', 'PASS01', '홍', 'G1', NULL, NULL, NULL);

INSERT INTO MEM
VALUES (2, 'USER02', 'PASS02', '김', 'G2', NULL, NULL, NULL);

INSERT INTO MEM
VALUES (3, 'USER03', 'PASS03', '황', 'G1', NULL, NULL, NULL);

- GRADE_CODE가 'G1'인 컬럼 삭제 시

DELETE FROM MEM_GRADE
WHERE GRADE_CODE = 'G1';

SELECT절을 통해 조회해보면

행1, 2는 NULL값으로 변하는 Result Set을 볼 수 있음.

ROLLBACK;
DROP TABLE MEM;
--다시 되돌린 뒤 테이블 구조 삭제

2) ON DELETE CASCADE : 부모데이터 삭제 시 해당 데이터를 사용하고 있는 데이터도 같이 삭제해버리는 옵션

- 테이블 생성

CREATE TABLE MEM(
    MEM_NO NUMBER PRIMARY KEY,
    MEM_ID VARCHAR2(20) NOT NULL UNIQUE,
    MEM_PWD VARCHAR2(20) NOT NULL,
    MEM_NAME VARCHAR2(20) NOT NULL,
    GRADE_ID CHAR(2), 
    GENDER CHAR(3) CHECK(GENDER IN('남', '여')),
    PHONE VARCHAR2(15), 
    EMAIL VARCHAR2(30),
    FOREIGN KEY(GRADE_ID) REFERENCES MEM_GRADE(GRADE_CODE) ON DELETE CASCADE
);

- 데이터 입력

INSERT INTO MEM
VALUES(1, 'USER01', 'PASS01', '홍길동', 'G1', NULL, NULL, NULL);

INSERT INTO MEM
VALUES(2, 'USER02', 'PASS02', '김길동', 'G2', NULL,NULL,NULL);

INSERT INTO MEM
VALUES (3, 'USER03', 'PASS03', '박길동', 'G1', NULL,NULL,NULL);

INSERT INTO MEM
VALUES (4, 'USER04', 'PASS04', '이길동', NULL ,NULL, NULL, NULL);

- NOT NULL 제약조건이 없는 GRADE_CODE는 NULL값도 입력 가능

DELETE FROM MEM_GRADE
WHERE GRADE_CODE = 'G1';

-> 문제없이 잘 삭제됨

조회해보면,

-> 자식테이블(MEM)의 GRADE_ID가 G1인 행들이 모두 함께 삭제됨(행)

 

- 실습)  전체회원의 회원번호, 아이디, 비밀번호, 이름, 등급명 조회

--ORACLE 
SELECT MEM_NO, MEM_ID, MEM_PWD, MEM_NAME, GRADE_NAME
FROM MEM, MEM_GRADE
WHERE GRADE_ID =GRADE_CODE(+);

--ANSI
SELECT MEM_NO, MEM_ID, MEM_PWD, MEM_NAME, GRADE_NAME 
FROM MEM
LEFT JOIN MEM_GRADE ON(GRADE_ID =GRADE_CODE);

DROP TABLE MEM;

하지만, JOIN을 하기 위해서 무조건 외래키 제약조건에 걸려있어야 하는 것은 아님

 

- 트랜잭션 : 아래와 같은 논리적 단위 => 뒤에서 자세히 다뤄볼 예정.

예시)    비밀번호 변경 처리 
    1. 아이디, 비밀번호를 입력해서 본인임을 확인
    SELECT MEM_ID, MEM_PWD
    FROM MEM
    WHERE MEM_ID = '사용자가 입력한 아이디'
        AND MEM_PWD = '사용자가 입력한 비밀번호';
        
    2. 기존의 비밀번호, 새로운 비밀번호 입력
    SELECT MEM_PWD WHERE 컬럼 = '기존의 비밀번호 == 새비밀번호'
    
    3. 기존의 비밀번호와 새로운 비밀번호가 다르다면 변경
     UPDATE MEM
        SET EME_PWD = '새로 입력한 비밀번호'
    WHERE MEM_ID = '아이디'
    AND MEM_PWD = '기존비밀번호';
    
    비밀번호 변경완료
    COMMIT;

 

-실행계정 : KH

 

(7)  SUBQUERY를 이용한 테이블 생성(복사뜨는 개념)

- SUBQUERY -> 메인 SQL문을 보조하는 쿼리문

[표현법]
    CREATE TABLE 테이블명
    AS 서브쿼리;

 

서브쿼리 수행결과(RESULT SET)으로 테이블을 생성하겠다.

 

① EMPLOYEE테이블을 복제한 새로운 테이블 생성(EMPLOYEE_COPY)

CREATE TABLE EMPLOYEE_COPY
    AS SELECT * FROM EMPLOYEE;

- 제약조건 NOT NULL만 복사됨 

SELECT * FROM EMPLOYEE_COPY;

② EMPLOYEE테이블에 있는 컬럼의 구조만 복사하고 싶은 경우 , 데이터값은 제외

CREATE TABLE EMPLOYEE_COPY2
    AS SELECT *
        FROM EMPLOYEE
        WHERE 1=0; --거짓, WHERE절엔 항상 참/ 혹은 거짓 출력이 되기에 거짓을 출력하면 구조만 출력됨

- 실습1) 전체 사원들 중 급여가 300만원 이상인 사원들의 사번, 이름, 부서코드, 급여 컬럼 복제

CREATE TABLE EMPLOYEE_COPY3
    AS SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY 
        FROM EMPLOYEE
        WHERE SALARY >= 3000000;

- 실습2) 전체 사원의 사번, 사원명, 급여, 연봉조회 결과 테이블 복제

CREATE TABLE EMPLOYEE_COPY4
    AS SELECT EMP_ID, EMP_NAME, SALARY, SALARY *12 "연봉" 
    --서브쿼리의 SELECT 절 산술연산 또는 함수식이 기술된 경우 앨리어스를 부여해야 함
    FROM EMPLOYEE;

③  테이블이 다 생성된 후 뒤늦게 제약조건 추가 (ALTER TABLE 테이블명 XXX) - 구조변경

    - PRIMARY KEY : ADD PRIMARY KEY(컬럼명);
    - FOROIGN KEY : ADD FORIGN KEY(컬럼명) REFERENCES 참조할 테이블명(참조할컬럼명)ㅣ
    - UNIQUE : ADD UNIQUE(컬럼명);
    - CHECK : ADD CHECK(컬럼에 대한 조건);
    - NOT NULL : MODIFY 컬럼명 NOT NULL;

 

- EMPLOYEE COPY 테이블에 없는 PRIMARY EMP_ID컬럼에 제약조건 추가

ALTER TABLE EMPLOYEE_COPY ADD PRIMARY KEY(EMP_ID);

-EMPLOYEE_COPY테이블에 DEPT_CODE컬럼에 외래키 제약조건 추가(DEPARTMENT의 DEPT_ID를 참조)

ALTER TABLE EMPLOYEE_COPY ADD FOREIGN KEY(DEPT_CODE) REFERENCES DEPARTMENT(DEPT_ID);

 

2) ALTER 

: 객체 구조를 수정하는 구문

 

    < 테이블 수정 > 
    ALTER TABLE 테이블명 수정할내용; 
  

  - 수정할 내용
    1) 컬럼 추가 / 수정 / 삭제
    2) 제약조건 추가 / 삭제 => 수정은 불가 (수정하고자하면 삭제 후 새롭게 추가)
    3) 테이블명 / 컬럼명 / 제약조건명 
    
    => 테이블 "구조"와 관련된 수정

(1) 컬럼 추가 / 수정 / 삭제 

1-1) 컬럼 추가(ADD) : ADD 추가할컬럼명 데이터타입 /*DEFAULT 기본값(생략가능)*/

- CNAME컬럼 추가 

ALTER TABLE DEPT_COPY ADD CNAME VARCHAR2(20);
 --새로 컬럼이 만들어지고 기본적으로 NULL값으로 채워짐

-LANME 컬럼 추가 DEFAULT 지정해서 '한국'으로 넣어보자

ALTER TABLE DEPT_COPY ADD LNAME VARCHAR(20) DEFAULT '한국';
 --새로 컬럼이 만들어지고 기본값이 NULL이 아닌 DEFAULT 값으로 채워짐
 
 ROLLBACK;

1_2_) 컬럼 수정(MODIFY)

 - 데이터 타입 수정 : MODIFY 수정할컬럼명 바꾸고자하는 데이터타입;
 - DEFAULT 값 수정 : MODIFY 수정할 컬럼명 DEFAULT 바꾸고자하는 기본값;
 
 - DEPT_ID컬럼의 데이터 타입을 CHAR(3)로 변경

 ALTER TABLE DEPT_COPY MODIFY DEPT_ID CHAR(3);

 - 현재 변경하고자하는 컬럼에 이미 담겨있는 값과 완전히 다른 타임으로 변경이 불가능
   예) 문자 -> 숫자(X) / 문자열 사이즈 축소(X) / 문자열 사이즈 확대(O)

 ALTER TABLE DEPT_COPY MODIFY DEPT_ID NUMBER; --=> column to be modified must be empty to change datatype
 ALTER TABLE DEPT_COPY MODIFY DEPT_TITLE VARCHAR(10); --=> 축소불가

- 실습) DEPT_TITLE컬럼의 데이터 타입을 VARCHAR2(40)으로
           LOCATION_ID 컬럼의 데이터타입을 VARCHAR2(3)으로
           LNAME컬럼의 기본값을 '미국'으로 변경

 ALTER TABLE DEPT_COPY 
 MODIFY DEPT_TITLE VARCHAR2(40)
 MODIFY LOCATION_ID VARCHAR2(3)
 MODIFY LNAME DEFAULT '미국';
 --> 하나로 합쳐도 됨

구조는 변경 되었으나

-> 데이터를 바꾸지 않았기 때문에 테이블 안에 데이터는 그대로 '한국'임

 CREATE TABLE DEPT_COPY2
    AS SELECT * FROM DEPT_COPY;

1_3) 컬럼삭제(DROP COLUMN) DROP COLUMN 삭제하고자 하는 컬럼명 

-DEPT_COPY2 테이블에서 DEPT_ID컬럼 지우기

ALTER TABLE DEPT_COPY2 DROP COLUMN DEPT_ID;

삭제됨

ROLLBACK;
--DDL구문은 복구가 불가능

- 모든 컬럼 삭제

ALTER TABLE DEPT_COPY2 DROP COLUMN DEPT_TITLE;
ALTER TABLE DEPT_COPY2 DROP COLUMN LOCATION_ID;
ALTER TABLE DEPT_COPY2 DROP COLUMN CNAME;
ALTER TABLE DEPT_COPY2 DROP COLUMN LNAME;
--마지막 컬럼을 삭제하려고 하면 : 테이블에 최소 한 개의 컬럼이 있어야 하므로 오류 발생

2) 제약조건 추가 / 삭제

2_1) 제약조건 추가

    NOT NULL : MODIFY 컬럼명 NOT NULL;
    UNIQUE : ADD UNIQUE(컬럼명)
    CHECK : ADD CHECK(컬럼명)
    PRIMARY KEY : ADD PRIMARY KEY(컬럼명)
    FOREIGN KEY : ADD FOREIGN KEY(컬럼명) REFERENCES 참조할테이블명(참조할컬럼명)

ALTER TABLE DEPT_COPY 
ADD CONSTRAINT DCOPY_PK PRIMARY KEY(DEPT_ID)
ADD CONSTRAINT DCOPY_UQ UNIQUE(DEPT_TITLE)
MODIFY LNAME CONSTRAINT DCOPY_NN NOT NULL;

2_2) 제약조건 삭제   

    PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK : DROP CONCTRAINT 제약조건명
    NOT NULL : MODIFY 컬럼명 NULL;

- DCOPY_PK 제약조건 지우기

ALTER TABLE DEPT_COPY DROP CONSTRAINT DCOPY_PK;

- LNAME의 제약조건 지우기 NOT NULL => NULL

ALTER TABLE  DEPT_COPY MODIFY LNAME NULL;

 

3) 컬럼명 / 제약조건명 / 테이블명 변경(RENAME)

3_1) 컬럼명 변경 : RENAME COLUMN 기준컬럼명 TO 바꿀컬럼명;

ALTER TABLE DEPT_COPY RENAME COLUMN DEPT_TITLE TO DEPT_NAME;

3_2) 제약조건명 변경 : RENAME CONSTRAINT 기존제약조건명 TO 바꿀제약조건명;

ALTER TABLE DEPT_COPY RENAME CONSTRAINT SYS_C007142 TO DCOPY_98;

3_3) 테이블명 변경 RENAME TO 바꿀테이블명;

ALTER TABLE DEPT_COPY RENAME TO DEPT_TEST;

3. DROP

- 객체를 삭제하는 구문

DROP TABLE DEPT_TEST;
ROLLBACK;

-어딘가에 참조되고 있는 부모테이블은 삭제 불가능

 만약 삭제하고 싶다면,

1) 자식테이블을 먼저 삭제하고 부모테이블을 삭제한다. 

DROP TABLE 자식테이블;
DROP TABLE 부모테이블;

2) 부모테이블만 삭제하는데 맞물려있는 제약조건도 함께 삭제한다.
DROP TABLE 부모테이블 CASCADE CONSTRAINT;


< DML : DATE MANIPULATION LANGAGE > 

데이터 조작어

 

테이블에 새로운 데이터를 삽입(INSERT)하거나, 기존의 데이터를 수정(UPDATE)하거나,삭제(DELETE)하는 구문

 

* DML - CRUD
    C(CREATE) : 추가 INSERT
    R(READ) : 조회   SELECT
    U(UPDATE) : 갱신  UPDATE
    D(DELETE) : 삭제  DELETE

 

1. INSERT : 테이블에 행을 추가하는 구문

[표현법]
    INSERT INTO 테이블명 VALUES(값, 값, 값 ...);
    => 해당테이블에 모든 컬럼에 값을 추가하고자 할 때 INSERT구문을 사용할 수 있음.
    
 주의사항 : 컬럼 순번을 지켜서 VALUES괄호 안에 나열해야 함

INSERT INTO EMPLOYEE
 VALUES (900, '박세*', '123123-1231234', 'park@clean.com', '01012345555', 'D1',
        'J1', 'S4', 50000000, 0.1, NULL,  SYSDATE, NULL, DEFAULT);

1-2) INSERT INTO 테이블명(컬럼명1, 컬럼명2, 컬럼명3, ...) VALUES (값1, 값2, 값3, ...)

 => 해당 테이블에 특정 컬럼만 선택해서 그 컬럼에 추가할 값만 제시하고자 할 때 사용

한 행 단위로 추가가 되기 때문에 선택이 안된 컬럼은 기본적으로 NULL값이 들어감
    (기본값 DEFAULT 지정 되어있을 경우 기본값이 들어감)

주의사항 : NOT NULL제약조건이 걸려있는 컬럼은 반드시 직접 값을 제시해야 함

INSERT INTO EMPLOYEE(EMP_ID, EMP_NAME, EMP_NO, DEPT_CODE, JOB_CODE, SAL_LEVEL, HIRE_DATE)
VALUES (901, '김광*', '456456-4564567', 'D2', 'J2', 'S3', SYSDATE);

1-3) INSERT INTO 테이블명(서브쿼리);

=> VALUES 로 값을 기입하는 것 대신에 서브쿼리로 조회한 결과값을 INSERT하는 구문

① 테이블 생성

CREATE TABLE EMP_01(
    EMP_ID NUMBER,
    EMP_NAME VARCHAR2(30),
    DEPT_TITLE VARCHAR2(20)
    );

② 데이터 삽입

INSERT INTO EMP_01
        (SELECT EMP_ID, EMP_NAME, DEPT_TITLE
        FROM EMPLOYEE, DEPARTMENT
        WHERE DEPT_CODE = DEPT_ID(+));

 2. INSERT ALL : 두 개 이상의 테이블에 각각 INSERT할 때 사용, 그 때 사용되는 서브쿼리가 동일한 경우

- 새로운 테이블을 먼저 만들기

- 첫 번째 테이블 : 급여가 300만원 이상인 사원들의 사번, 사원명, 직급명에 대해 보관할 테이블

- 테이블 이름 : EMP_JOB
- 컬럼 : EMP_ID NUMBER, EMP_NAME VARCHAR2(30), JOB_NAME VARCHAR2(20)

CREATE TABLE EMP_JOB(
        EMP_ID NUMBER, 
        EMP_NAME VARCHAR2(30), 
        JOB_NAME VARCHAR2(20)
);

- 두 번째 테이블 : 급여가 300만원 이상인 사원들의 사번, 사원명, 부서명에 대해 보관할 테이블

- 테이블 이름 : EMP_DEPT
- 컬럼 : EMP_ID NUMBER, EMP_NAME VARCHAR2(30), DEPT_TITLE VARCHAR2(20)

CREATE TABLE EMP_DEPT(
            EMP_ID NUMBER, 
            EMP_NAME VARCHAR2(30), 
            DEPT_TITLE VARCHAR2(20)
);

 - 급여가 300만원 이상인 사번, 이름, 부서명, 직급명 조회

SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
WHERE SALARY >= 3000000;

    [표현법]

    INSERT ALL
    INTO 테이블명1 VALUES(컬럼명, 컬럼명, 컬럼명)
    INTO 테이블명2 VALUES(컬럼명, 컬럼명, 컬럼명)
    서브쿼리;

- EMP_JOB 테이블에는 급여가 300만원 이상인 사원들의 EMP_ID, EMP_NAME, JOB_NAME

- EMP_DEPT 테이블에는 급여가 300만원 이상인 사원들의 EMP_ID, EMP_NAME, DEPT_TITLE

INSERT ALL
    INTO EMP_JOB VALUES(EMP_ID, EMP_NAME, JOB_NAME)
    INTO EMP_DEPT VALUES(EMP_ID, EMP_NAME, DEPT_TITLE)
    SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
    FROM EMPLOYEE
    JOIN JOB USING(JOB_CODE)
    LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
    WHERE SALARY >= 3000000;

- 실습)  사번, 사원명, 입사일, 급여 // EMP_OLE, EMP_NEW

- 구조만 복사

CREATE TABLE EMP_OLD
    AS SELECT EMP_ID,EMP_NAME, HIRE_DATE, SALARY
        FROM EMPLOYEE
        WHERE 0=1;
CREATE TABLE EMP_NEW
    AS SELECT EMP_ID, EMP_NAME, HIRE_DATE, SALARY
        FROM EMPLOYEE
        WHERE 0=1;

- INSERT ALL을 사용해 2010/01/01 이전에 입사한 사원은 EMP_OLD, 이후 입사한 사원은 EMP_NEW에 삽입

    INSERT ALL
    WHEN HIRE_DATE < '2010/01/01' THEN
    INTO EMP_OLD VALUES(EMP_ID, EMP_NAME, HIRE_DATE, SALARY)
    WHEN HIRE_DATE >= '2010/01/01' THEN
    INTO EMP_NEW VALUES(EMP_ID, EMP_NAME, HIRE_DATE, SALARY)
    SELECT EMP_ID, EMP_NAME, HIRE_DATE, SALARY
    FROM EMPLOYEE;

3. UPDATE : 테이블에 기록된 데이터를 수정하는 구문

        [표현법]
        UPDATE 테이블명
            SET 컬럼명 = 바꿀값
                ,컬럼명 = 바꿀값
                ,컬럼명 = 바꿀값 => 여러개의 컬럼을 동시 변경 가능 (쉼표, 곡 사용하기)
            WHERE 조건 ; => 생략이 가능, 생략 시 전체 모든 행의 데이터가 다 변경.> 그냥 꼭 사용하기

- 테이블 복사

    CREATE TABLE DEPT_COPY
        AS SELECT * 
            FROM DEPARTMENT;

-부서코드가 D9인 부서명(총무부) 변경 전략기획부로 수정 

UPDATE DEPT_COPY
        SET DEPT_TITLE = '전략기획부'
   WHERE DEPT_ID = 'D9';

- 테이블복사2

CREATE TABLE EMP_SALARY
    AS SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY, BONUS
     FROM EMPLOYEE;

- EMP_SALARY테이블에 김광* 사원의 급여를 1000만원으로 변경

    UPDATE EMP_SALARY
        SET SALARY = 10000000
        WHERE EMP_NAME = '김광*';

- 전체사원의 급여를 기존급여에서 20% 인상한 금액으로 변경

    UPDATE EMP_SALARY
        SET SALARY = SALARY*1.2;

3-1) UPDATE 시에 서브쿼리를 사용
      : 서브쿼리를 수행한 결과값으로 UPDATE
[표현법]    

    UPDATE 테이블명
            SET 컬럼명 = (서브쿼리)
         WHERE 조건; => 생략 가능

 

- EMP_SALARY테이블에 김광* 사원의 부서코드를 박세* 사원의 부서코드로 변경

    UPDATE EMP_SALARY
        SET DEPT_CODE = (SELECT DEPT_CODE
                            FROM EMPLOYEE
                            WHERE EMP_NAME = '박세*')
            WHERE EMP_NAME = '김광*';

- 방명수 사원의 급여와 보너스를 유재식 사원의 급여와 보너스 값으로 변경

UPDATE EMP_SALARY
        SET (SALARY, BONUS) = (SELECT SALARY, BONUS
                                FROM EMPLOYEE
                                WHERE EMP_NAME = '유재식')
        WHERE EMP_NAME = '방명수';

- UPDATE 사용 시 수정할 때 아무런 문제가 없을까?

- 송종기 사원의 사번을 200번으로 변경 

- 제약조건을 떠올려보면,

    UPDATE EMPLOYEE
        SET EMP_ID = 200
        WHERE EMP_NAME  = '송종기'; --> PRIMARY KEY제약조건에 위배
        
    UPDATE EMPLOYEE
        SET EMP_NAME = NULL
    WHERE EMP_NAME = '송종기'; --> NOT NULL 제약조건에 위배

4. DELETE :  테이블에 기록된 데이터를 삭제하는 구문

        [표현법]
        DELETE FROM 테이블명
        WHERE 조건; => WHERE 절은 생략가능. 생략 시 해당테이블의 전체 행 삭제 

    DELETE FROM EMPLOYEE;
    SELECT * FROM EMPLOYEE;
    ROLLBACK; --> 롤백 시 마지막 커밋시점으로 돌아감

- 박세*, 김광* 사원의 데이터 지우기

    DELETE FROM EMPLOYEE
    WHERE EMP_NAME IN('김광진', '박세정');
    
    COMMIT;--모든 변경사항을 확정 함

- DEPARTMENT 테이블로부터 DEPT_ID가 D1인 부서 삭제

    DELETE FROM DEPARTMENT 
    WHERE DEPT_ID = 'D1'; -- 이미 사용하고 있는 코드이기 때문에 오류 발생
    
    DELETE FROM DEPARTMENT
    WHERE DEPT_ID = 'D3'; -- 사용하지 않는 부서는 정상적으로 삭제 됨

4-1)  TRUNCATE : 테이블의 전체 행을 삭제할 때 사용하는 구문(절삭)

DELETE보다 수행 속도가 더 빠름 / 별도의 조건 제시 불가, ROLLBACK 불가능

[표현법]
TRUNCATE TABLE 테이블명 DELETE FROM 테이블명
별도의 조건 제시 불가 특정 조건 제시 가능
수행속도 빠름 (DELETE보다) 수행 속도가 느림(TRUNCATE보다)
 ROLLBACK 불가 ROLLBACK가능
    SELECT * FROM EMP_SALARY;
    DELETE FROM EMP_SALARY; -- 0.041초
    ROLLBACK;
    
    TRUNCATE TABLE EMP_SALARY; -- 0.104초
    --Table EMP_SALARY이(가) 잘렸습니다.

 

 < DCL : DATA CONTROL LANGUAGE > 

    데이터 제어언어
    GRANT, REVOKE

: 계정에게 객체 접근권한, 시스템 권한을 부여(GRANT)하더나, 회수(REVOKE)하는 언어

    * 권한 부여(GRANT)
    - 시스템권한 : 특정 DB에 접근한느 권한, 객체들을 생성할 수 있는 권한
    - 객체 접근 권한 : 특정 객체들에 접근해서 조작할 수 있는 권한
    
    [표현법]
    GRANT 권한1, 권한2,...TO 계정명;
    
    - CREATE SESSION : 계정에 접속할 수 있는 권한 
    - CREATE TABLE : 테이블을 생성할 수 있는 권한
    - CREATE VIEW : 뷰를 생성할 수 있는 권한 
    - CREATE SEQUENCE : 시퀀스를 생성할 수 있는 권한
    - CREATE USER : 계정을 생성할 수 있는 권한
    ....

1. SAMPLE 계정 생성

CREATE USER SAMPLE IDENTIFIED BY SAMPLE;

2. SAMPLE 계정에 접속하기 위한 CREATE SESSION 권한 부여

GRANT CREATE SESSION TO SAMPLE;
-- SAMPLE계정
CREATE TABLE TEST(
TEST_ID NUMBER
);

- 3_1. SAMPLE계정에 테이블을 생성할 수 있는 권한이 없기 때문에 오류 발생
- ORA-01031: insufficient privileges

- SAMPLE계정에 테이블을 생성할 수 있는 CREATE TABLE권한 부여

GRANT CREATE TABLE TO SAMPLE;
--SAMPLE계정
--CREATE TABLE 권한 부여 받은 후 
CREATE TABLE TEST(
TEST_ID NUMBER
);

- 3_2. TABLESPACE가 할당되지 않아서 오류 발생 -->데이터를 저장할 물리적 장소

- ORA-01950: no privileges on tablespace 'SYSTEM'

-  SAMPLE계정에 테이블스페이스를 할당해주기(SYSTEM 계정 변경)

ALTER USER SAMPLE QUOTA 2M ON SYSTEM;
--SAMPLE계정
--TABLE SPACE 할당 받은 후 
CREATE TABLE TEST(
TEST_ID NUMBER
);

-테이블 생성완료

테이블 생성 권한을 부여받게 되면, 계정이 '소유'하고 있는 테이블들을 조작하는 것도 가능

SELECT * FROM TEST;
INSERT INTO TEST VALUES(1);

-뷰 만들어보기

CREATE VIEW V_TEST 
    AS SELECT * FROM TEST;

4. 뷰 객체를 생성할 수 있는 CRATE VIEW권한이 없기 때문에 오류 발생
-ORA-01031: insufficient privileges

- SAMPLE계정에 뷰를 생성할 수 있는 CREATE VIEW 권한 부여

GRANT CREATE VIEW TO SAMPLE;
--SAMPLE계정
CREATE VIEW V_TEST
    AS SELECT * FROM TEST;

 

* 객체권한

특정객체를 조작(SELECT, INSERT, DELETE, UPDATE)할 수 있는 권한

 

 [표현법]
 GRANT 권한종류 ON 특정객체 TO 계정명;

 [객체 권한의 종류]
 SELECT | TABLE, VIEW, SEQUENCE
 INSERT | TABLE, VIEW
 UPDATE | TABLE, VIEW
 DELETE | TABLE, VIEW

 

- SAMPLE 계정에서 KH계정의 테이블에 접근해서 조회해보기

SELECT *
FROM KH.EMPLOYEE;

5. KH계정의 테이블에 접근해서 조회할 수 있는 권한이 없기 때문에 오류 발생
- ORA-00942: table or view does not exist

- SAMPLE계정에서 KH.EMPLOYEE테이블을 조회할 수 있는 권한 부여 

GRANT SELECT ON KH.EMPLOYEE TO SAMPLE;
--SAMPLE계정
SELECT *
FROM KH.EMPLOYEE;
--EMPLOYEE테이블 조회 성공!

- SAMPLE 계정에서 KH계정의 테이블에 접근해서 행 삽입해보기

INSERT INTO KH.DEPARTMENT VALUES('D0', '회계부', 'L2');

6. KH계정의 DEPARTMENT테이블에 접근할 수 있는 권한이 없기 때문에 오류

- SAMPLE계정에 KH.DEPARTMENT테이블에 행을 삽입할 수 있는 권한 부여 

GRANT INSERT ON KH.DEPARTMENT TO SAMPLE;
INSERT INTO KH.DEPARTMENT VALUES('D0', '회계부','L2');
--> 성공
ROLLBACK;

* 권한 회수(REVOKE) : 권한을 회수할 때 사용하는 명령어

   [표현법]
    REVOKE 권한1, 권한2... FROM 사용자이름;

 

1. SAMPLE계정에서 테이블을 생성할 수 없도록 권한회수

REVOKE CREATE TABLE FROM SAMPLE;

-만약 7실행 후 테이블 생성시

CREATE TABLE TEST2(
TEST_ID NUMBER
);
--7. SAMPLE계정에서 테이블을 생성할 수 없도록 권한을 회수했기 때문에 오류발생

* GRANT CONNECT, RESOURCE TO 계정

-최소한의 권한을 부여하고자할 때 CONNECT, RESOURCE만 부여하면 된다.

CONNECT, RESOURCE도 테이블에 저장되어있음.

SELECT *
FROM R0LE_SYS_PRIVS
WHERE ROLE IN('CONNECT', 'RESOURCE');

< 롤 ROLE > 

- 특정 권한들을 하나의 집합으로 모아놓은 것

    CONNECT : CREATE SESSION (데이터베이스에 접속할 수 있는 권한)
    RESOURCE : CREATE TABLE, CREATE VIEW (특정 객체들을 생성 및 관리하는 권한)

 

- 실습) 사용자에게 부여할 권한 : CONNECT, RESOURCE

          권한을 부여받을 사용자 : HAHA

          권한 부여 후 USER 객체 삭제

CREATE USER HAHA IDENTIFIED BY HAHA;
GRANT CONNECT, RESOURCE TO HAHA;
DROP USER HAHA;

 < TCL : TRANSACTION CONTROL LANGUAGE >

* 트랜잭션(TRANSACTION)

    - 작업단위 
    - 데이터베이스의 논리적 연산단위
    - 데이터의 변경사항(DML)들을 하나의 트랜잭션으로 묶어서 처리 
    COMMIT(확정)하기 전까지는 변경사항들을 하나의 트랜잭션에 담는다. 
    - 트랜잭션에 대상이 되는 SQL : DML(INSERT, UPDATE, DELETE) * SELECT는 데이터에 영향을 미치지 않음 * 

    COMMIT(트랜잭션 종료처리 후 확정)
    ROLLBACK (트랜잭션 취소)
    SAVAPOINT (임시저장)

 

- 테이블명 : EMP_02

- EMPLOYEE 테이블 복사

    CREATE TABLE EMP_02
        AS SELECT * FROM EMPLOYEE;

- 사번이 221인 사원 삭제

DELETE FROM EMP_02
WHERE EMP_ID = 221;

- 사번이 220인 사원 삭제

DELETE FROM EMP_02
WHERE EMP_ID = 220;

- 사번이 800, 이름 홍길동인 사원 추가

INSERT INTO EMP_02(EMP_NO, EMP_ID, EMP_NAME, JOB_CODE, SAL_LEVEL) 
VALUES('11111-2222222', 800, '홍길동', 'J9', 'S1');

- @주의 : NOT NULL == EMP_ID, EMP_NAME, EMP_NO, JOB_CODE, SAL_LEVEL

COMMIT; --> 확정

SELECT * FROM EMP_02;

ROLLBACK; --> 마지막 커밋으로 돌아감

SELECT * FROM EMP_02;

- 사번이 217, 216, 214인 사원 삭제

DELETE FROM EMP_02
WHERE EMP_ID IN(217, 216, 214);

-3개행이 삭제된 시점에서 SAVEPOINT 지정

SAVEPOINT SP1;

- 사번이 200인 사원 삭제

DELETE FROM EMP_02
WHERE EMP_ID = 200;

- SAVEPOINT로 롤백 시,

ROLLBACK TO SP1;

COMMIT;

-> SP1 로 돌아감 200인 사원 삭제는 적용되지 않음

 

-사번이 800인 사원 없애기

DELETE FROM EMP_02
WHERE EMP_ID = 800;

-테이블생성(DDL)

CREATE TABLE TEST(
TID NUMBER
);

ROLLBACK;

     DDL구문(CREATE, ALTER, DROP) 을 실행하는 순간
     기존에 트랜잭션에 있는 모든 변경사항들을 무조건 실제 DB에 반영(COMMIT)
     그 다음에 DDL이 수행됨

    => DDL수행 전 변경사항이 있다면 정확히 fix(COMMIT, ROLLBACK)하고 DDL을 수행해야 함

 

    COMMIT : 하나의 트랜잭션에 담겨있는 변경사항들(DML)을 실제 DB에 반영하겠다.
            실제 반영시킨 후 트랜잭션은 비워짐
    ROLLBACK : 하나의 트랜잭션에 담겨있는 변경사항들(DML)을 삭제한 후 
            마지막 COMMIT 시점으로 돌아감
    SAVEPOINT : 지금 시점 임시저장점 정의

 

-정리해보면,

 DDL : CREATE(만들고), ALTER(고치고), DROP(버리고)
 DML : SELECT(조회) / INSERT(삽입), UPDATE(갱신), DELETE(삭제) *************
 DCL : GRANT(주기), REVOKE(뺏기)
 TCL : COMMIT(확정), ROLLBACK(돌아가기), SAVEPOINT(중간저장) ************ DML을 하면 무조건 COMMIT/ROLLBACK해야함