본문 바로가기

oracle SQL

2024.12.16 13일차 수업

# CTAS 복제 복습

create table hr.emp_copy
tablespace users
as select * from hr.employees;
desc hr.emp_copy;

출력

# 소유자 관점(만든 사람) 테이블 정보 확인

select * from user_tables where table_name = 'EMP_COPY';

출력

 

# DBA 관점에서 테이블 정보 확인

select * from dba_tables where owner = 'HR' and table_name = 'EMP_COPY';

출력

 

#  소유자 관점 컬럼 정보 확인

select * from user_tab_columns where table_name = 'EMP_COPY';

출력

 

# DBA 관점에서 컬럼 정보 확인 (dba)

select * from dba_tab_columns where owner = 'HR' and table_name = 'EMP_COPY';

출력

 

# 컬럼을 추가하는 방법 (hr)

alter table hr.emp_copy add department_name varchar2(30);

select * from user_tab_columns where table_name = 'EMP_COPY';

출력

 

문제) emp_copy 테이블에 department_name은 값이 없어서 null로 되어있다. departments테이블에 department_name을 가져오고 싶을 때 어떡해야 할까?

 

1) correlated subquery를 이용한 update문

update hr.emp_copy e
set department_name = (select department_name
                        from hr.departments
                        where department_id = e.department_id);

 

2) merge문

merge into hr.emp_copy e --target table (실제 업데이트가 되는 곳)
using hr.departments d  --source table
on (e.department_id = d.department_id)
when matched then
		update set e.department_name = d.department_name;

출력

 

# merge문에도 서브쿼리를 쓸 수 있다.
  - using절에 쓸 수 있고 꼭 괄호로 묶어줘야 한다.

merge into hr.emp_copy e 
using (select department_id, department_name 
from hr.departments) d  
on (e.department_id = d.department_id)
when matched then
		update set e.department_name = d.department_name;
        
rollback;

 

1. 컬럼 타입, 크기를 수정

 

   # 수정 전

desc hr.emp_copy;

select * from user_tab_columns where table_name = 'EMP_COPY';

출력

select * from user_tab_columns where table_name = 'EMP_COPY';

출력

  # job_id의 크기를 바꾸고 싶을 경우

alter table hr.emp_copy modify job_id varchar2(20);

출력

select * from user_tab_columns where table_name = 'EMP_COPY';

출력

# job_id 길이 확인

select job_id, length(job_id) from hr.emp_copy;

출력

alter table hr.emp_copy modify job_id varchar2(5);

출력

▶ 오류 뜨는 이유는 현재 값이 들어있는 상태에서 5바이트 보다 큰 값이 들어있기 때문에 오류가 나온다.

 

alter table hr.emp_copy modify job_id number(20);

출력

▶ 이미 문자로 데이터값이 들어가 있기 때문에 오류가 나온다.

 

2. 컬럼 삭제

alter table hr.emp_copy drop column job_id; --  alter는 자동 커밋이 되기때문에 주의해야 한다.
select * from user_tab_columns where table_name = 'EMP_COPY';

출력

▶ job_id가 삭제된 걸 볼 수 있다.

 

■ 제약 조건

  - 데이터의 대한 규칙을 만든다.

  - 데이터의 대한 품질을 향상하기 위해서 만든다. (궁극적인 목표)

 

   1. primary key

      - 테이블의 대표키(기본키)

      - unique(유일한 값), null값은 허용할 수 없다. (NOT NULL)

      - 테이블당 무조건 하나 생성

      - 자동으로 unique index 생성

 

# 제약조건 정보 확인 (소유자)

 select * from user_constraints where table_name = 'EMPLOYEES'; -- 출력 1
 select * from user_cons_columns where table_name = 'EMPLOYEES'; -- 출력 2

출력 1
출력 2

# 제약조건 정보 확인 (DBA)

   select * from dba_constraints where owner = 'HR' and table_name = 'EMPLOYEES'; -- 출력 1
   select * from dba_cons_columns where owner = 'HR' and table_name = 'EMPLOYEES'; -- 출력 2

출력 1
출력 2

 

# primary key 제약조건 추가

   - 고유 이름으로 제약조건을 걸어야 한다.

alter table hr.emp_copy add constraint emp_id_pk primary key(employee_id);

출력

# index 정보 확인

select * from user_indexes where table_name = 'EMP_COPY'; -- 출력 1
select * from user_ind_columns where table_name = 'EMP_COPY'; -- 출력 2

출력 1
출력 2

# 제약조건 삭제

alter table hr.emp_copy drop constraint emp_id_pk;
select * from user_indexes where table_name = 'EMP_COPY'; -- 출력 1
select * from user_ind_columns where table_name = 'EMP_COPY'; -- 출력 2

출력 1
출력 2

 

# primar key 제약조건 추가

  - 제약조건 이름을 생략하게 되면 자동으로 sys_c숫자 형식의 이름으로 생성된다.

  - 위에처럼 이름을 줘서 하는 게 좋다.

alter table hr.emp_copy add primary key(employee_id);
select * from user_indexes where table_name = 'EMP_COPY'; -- 출력 1
select * from user_ind_columns where table_name = 'EMP_COPY'; -- 출력 2

출력 1
출력 2

 

# 제약조건 삭제 다른 방법

alter table hr.emp_copy drop constraint SYS_C007027;
또는
alter table hr.emp_copy drop primary key;
select * from user_indexes where table_name = 'EMP_COPY'; -- 출력 1
   select * from user_ind_columns where table_name = 'EMP_COPY'; -- 출력 2

출력 1
출력 2

 

# 샘플 테이블 삭제

drop table hr.emp_copy purge;
drop table hr.emp purge;
drop table hr.dept purge;

 

# 테이블 생성

create table hr.emp(id number, name varchar2(30), day date)
tablespace users;

 

   ## 사원ID도 같고 고유값에 null이 들어가면 성능적으로 안 좋다.

insert into hr.emp(id, name, day)
values(1, 'sql', sysdate);

insert into hr.emp(id, name, day)
values(1, 'psql', sysdate);

insert into hr.emp(id, name, day)
values(null, 'itwill', sysdate);

select * from hr.emp;

rollback;

출력

   ## primary key 추가

alter table hr.emp add constraint emp_id_pk primary key(id);
insert into hr.emp(id, name, day)
values(1, 'sql', sysdate);

insert into hr.emp(id, name, day)
values(1, 'psql', sysdate);
-> 다시 실행하면 오류 뜬다. 이유는 primary key로 제약조건을 걸었기 때문이다.

insert into hr.emp(id, name, day)
values(null, 'itwill', sysdate);
-> 다시 실행하면 오류 뜬다. 이유는 primary key로 제약조건을 걸었기 때문이다.
select * from hr.emp;
rollback;

출력

▶ pk값으로 id를 지정했는데 같은 id가 또 들어오면 에러를 발생하고, pk값에는 null이 허용되지 않기 때문에 null을 입력하면 에러가 뜬다.

 

# 테이블 생성 (PK 추가, 데이터 추가)

create table hr.dept(dept_id number, dept_name varchar2(30))
tablespace users;

alter table hr.dept add constraint dept_pk primary key(dept_id);
select * from user_constraints where table_name = 'DEPT'; -- 출력 1
   select * from user_cons_columns where table_name = 'DEPT'; -- 출력 2

 select * from user_indexes where table_name = 'DEPT'; -- 출력 3
   select * from user_ind_columns where table_name = 'DEPT'; -- 출력 4

출력 1
출력 2
출력 3
출력 4

    ## 데이터 값 넣기

insert into hr.dept(dept_id, dept_name) values(10,'총무팀');
insert into hr.dept(dept_id, dept_name) values(20,'인사팀');
commit;
select * from hr.dept;

출력


desc hr.emp; -- 출력 1
alter table hr.emp add dept_id number;
desc hr.emp; -- 출력 2

출력 1
출력 2

 

    ex)

insert into hr.emp(id, name, day, dept_id) values(1,'홍길동', sysdate, 10);
insert into hr.emp(id, name, day, dept_id) values(2,'박찬호', sysdate, 30); -- 없는 부서 코드

commit;
select * from hr.emp;

출력

 

ex) outer join

 select e.*, d.*
from hr.emp e, hr.dept d
where e.dept_id = d.dept_id(+); -- 출력 1

delete from hr.emp; 
commit;
select * from hr.emp; -- 출력 2

출력 1
출력 2

 

■ foreign key
   - 외래키, 참조 무결성 제약조건이라고 함
   - 동일한 테이블이나 다른 테이블의 primary key, unique key 제약조건만 참조한다.
   - 데이터 품질때문에 한다.
   - 중복값 허용null값 허용

 

 

select * from user_constraints where table_name in ('EMP','DEPT'); -- 출력 1
   select * from user_cons_columns where table_name in ('EMP','DEPT'); -- 출력 2
 select * from user_indexes where table_name in ('EMP','DEPT'); -- 출력 3
   select * from user_ind_columns where table_name in ('EMP','DEPT'); -- 출력 4

출력 1
출력 2
출력 3
출력 4

  # foreign key 추가

alter table hr.emp add constraint emp_dept_id_fk foreign key(dept_id)
references hr.dept(dept_id);
select * from user_constraints where table_name in ('EMP','DEPT'); -- 출력 1
   select * from user_cons_columns where table_name in ('EMP','DEPT'); -- 출력 2
 select * from user_indexes where table_name in ('EMP','DEPT'); -- 출력 3
   select * from user_ind_columns where table_name in ('EMP','DEPT'); -- 출력 4

출력 1
출력 2
출력 3
출력 4

 

  ## 데이터값 추가

insert into hr.emp(id, name, day, dept_id) values(1,'홍길동', sysdate, 10);

insert into hr.emp(id, name, day, dept_id) values(2,'박찬호', sysdate, 30); -- 오류나옴
-> pk에 없는 값이 입력됐기 때문이다.

select * from hr.emp;

commit;

출력
오류

insert into hr.emp(id, name, day, dept_id) values(2,'박찬호', sysdate, null);
commit;
select * from hr.emp;

출력

▶ null은 허용되기 때문에 출력이 된다.


# 테이블 조회

select * from hr.emp;

select * from hr.dept;
delete from hr.dept where dept_id = 10;

▶ 오류 발생한다. 이유는 foreign key 제약조건이 걸려 있으면서 10번 부서에 해당하는 사원정보가 존재하기 때문에 삭제가 오류 발생한다.

 

delete from hr.dept where dept_id = 20;

▶ 수행이 된다. 이유는 20번 부서에 해당하는 사원정보가 존재하지 않기 때문에 삭제가 수행된다.

 

select * from user_constraints where table_name in ('EMP','DEPT'); 

alter table hr.dept drop primary key;
또는
alter table hr.dept drop constraint dept_pk;

▶ 삭제가 안 된다. primary key 제약조건을 삭제하려고 하는 순간 foreign key 제약조건이 걸려 있으면 foreign key 제약조건을 먼저 삭제한 후 primary key 제약조건을 삭제하면 된다.

 

   # 해결방법

      1) foreign key 제약조건 삭제

alter table hr.emp drop constraint emp_dept_id_fk;

       2) primary key 제약조건 삭제

alter table hr.dept drop constraint primary key;

 

 

## 해결방법 2 - 훨씬 간편함

alter table hr.dept drop primary key cascade;

select * from user_constraints where table_name in ('EMP','DEPT');

▶ cascade (옵션) : 나를 참조하는 제약조건을 삭제하고, primary key 제약조건을 삭제

출력

 

3. unique 제약조건

   - 유일한 값만 체크

   - null 허용한다.

   - 자동으로 unique index 생성

 

select * from user_constraints where table_name in ('EMP','DEPT'); -- 출력 1
   select * from user_cons_columns where table_name in ('EMP','DEPT'); -- 출력 2

# unique 제약조건 걸기

select * from hr.dept;
   alter table hr.dept add constraint dept_name_uk unique(dept_name);

출력 1
출력 2

# 데이터 추가

insert into hr.dept(dept_id, dept_name) values(30,'총무팀');

출력

▶ 오류 발생이유는 dept_name에 unique 제약조건이 생성되어 있어서 중복되는 값은 입력될 수 없다.

 

insert into hr.dept(dept_id, dept_name) values(30, null);

▶ null은 허용이기 때문에 출력이 된다.

출력

update hr.dept
   set dept_name = '인사팀'
   where dept_id = 30;

▶ 오류 발생한다. 중복되는 값은 무조건 에러 뜬다.

출력

 

# unique 제약조건 삭제하는 방법 (시험에도 많이 나옴)

select * from user_constraints where table_name in ('EMP','DEPT');

 

1) 

alter table hr.dept drop constraint dept_name_uk;

 

 2)

alter table hr.dept drop unique(dept_name);

▶ 마지막에 dept_name 컬럼을 꼭 입력해줘야 한다.

 

select * from user_constraints where table_name in ('EMP','DEPT');

출력

▶ uk가 삭제된 걸 볼 수 있다.

 

4. check 제약조건

   - 조건값이 true인 경우 insert, update할 수 있도록 만드는 제약조건

   - null 허용, 중복값 허용한다.

 

desc hr.emp; -- 출력 1

alter table hr.emp add sal number;

desc hr.emp; -- 출력 2

출력 1
출력 2

alter table hr.emp add constraint emp_sal_ck check(sal >= 1000 and sal <= 2000);

select * from user_constraints where table_name in ('EMP','DEPT');

 

출력

▶ 조건식에 between을 써도 가능하다.

 

# 데이터 추가

insert into hr.emp(id, name, day, dept_id, sal)
values(3, '손흥민', sysdate, 20, 1500);

select * from hr.emp;

commit;

출력

 

# 에러 발생

insert into hr.emp(id, name, day, dept_id, sal)
values(4, '이문세', sysdate, 10, 500);

출력

▶ check 제약조건에 위반되었기 때문에 오류 발생

 

#  null

insert into hr.emp(id, name, day, dept_id, sal)
values(4, '이문세', sysdate, 10, null);

commit;

select * from hr.emp;

출력

 

# 에러

update hr.emp
set sal = 3000
where id = 4;

▶ check 제약조건에 위반되었기 때문에 오류 발생

 

# 출력

update hr.emp
set sal = 1500
where id = 4;

출력

# check 제약조건 삭제

alter table hr.emp drop constraint emp_sal_ck;

select * from user_constraints where table_name in ('EMP','DEPT');

출력

 

5. NOT NULL 제약조건

   - null값을 허용할 수 없는 제약조건

   - 중복 허용한다.

select * from user_constraints where table_name in ('EMP','DEPT'); --출력 1

desc hr.emp; -- 출력 2

출력 1
출력 2

▶ 출력 2 : NOT NULL이라고 보여지지만 내부적으론 PK이기 때문에 CTAS 때 복제가 안 된다.

 

insert into hr.emp(id, name, day, dept_id, sal)
values(5, null, sysdate, 10, 1000);

출력

▶ 이름이 null일 순 없으므로 무조건 값을 입력해줘야 한다.

 

rollback;

alter table hr.emp add constraint emp_name_nn not null(name); --기존 추가방식

출력

▶ 유효한 식별자가 아니기 때문에 오류 뜬다.

 

# 제약조건 추가 방법 (NOT NULL) - modify 이용

alter table hr.emp modify name constraint emp_name_nn not null;

select * from user_constraints where table_name in ('EMP','DEPT');

출력

 

# 오류 1

insert into hr.emp(id, name, day, dept_id, sal)
values(5, null, sysdate, 10, 1000);

▶ 위에서 넣었던 코드를 다시 입력하면 오류 뜬다. 이유는 NOT NULL 제약조건이 걸려있을 땐 null을 허용할 수 없기 때문이다.

 

ex) 오류 2

update hr.emp
set name = null
where id = 1;

출력

 

desc hr.emp;

출력

 

# NOT NULL 제약조건 삭제

select * from user_constraints where table_name in ('EMP','DEPT'); -- 출력 1

alter table hr.emp drop constraint emp_name_nn;
또는
alter table hr.emp modify name null;

select * from user_constraints where table_name in ('EMP','DEPT'); -- 출력 2

출력 1
출력 2

# 테이블 삭제

drop table hr.emp purge;
drop table hr.dept purge;

 

# 테이블 생성

create table hr.dept(
            dept_id number constraint dept_id_pk primary key,
            dept_name varchar2(30) constraint dept_name_uk unique)
tablespace users;

select * from user_constraints where table_name in ('EMPLOYEES','DEPARTNEBTS');

출력

▶ 에러 나오는 이유는 동일한 제약조건 이름이 있기 때문에 오류가 뜬다.

 

★ 제약조건 이름은 유저 레벨에서 고유한 이름으로 생성해야 한다.

 

# 해결방법

create table hr.dept(
            dept_id number constraint dept_pk primary key,
            dept_name varchar2(30) constraint dept_name_uk unique)
tablespace users;

출력

 

# 테이블 삭제 후 다시 생성

create table hr.dept(
            dept_id number primary key,
            dept_name varchar2(30) unique)
tablespace users;

select * from user_constraints where table_name in ('EMP','DEPT');

출력

▶constraint를 안 적고 실행하면 매우 불편하고 현장에선 거의 안 쓰기 때문에 이름을 표현하는 습관을 가지자

 

# emp 테이블 생성

create table hr.emp(
            id number constraint emp_id_pk primary key,
            name varchar2(30) constraint emp_name_nn not null,
            sal number,
            dept_id number constraint emp_dept_id_fk references hr.dept(dept_id),
            constraint emp_name_uk unique(name),
            constraint emp_sal_ck check(sal between 1000 and 2000))
tablespace users;

select * from user_constraints where table_name in ('EMP','DEPT');

출력

▶ 컬럼을 정의하면서 제약조건을 만드는 형식을 열 레벨 정의라고 표현하고, 열 정의를 다하고 나서 constraint 하는 걸 이블 레벨 정의라고 한다. 편한 걸로 하면 된다.

not null 제약조건열 레벨 정의로만 해야 한다!

 

create table hr.emp(
            id number,
            name varchar2(30) constraint emp_name_nn not null, -- 열 레벨 정의
            
            sal number,
            dept_id number,
            constraint emp_id_pk primary key(id), -- 테이블 레벨 정의
            constraint emp_name_uk unique(name),
            constraint emp_sal_ck check(sal between 1000 and 2000),
            constraint emp_dept_id_fk foreign key(dept_id) references 
            hr.dept(dept_id))
tablespace users;

▶ 테이블 레벨 정의할 때는 마지막에 컬럼명을 꼭 적어줘야 한다.

▶ 제약조건을 꼭 하나만 걸 수 있는 것은 아니다. 위에 보면 unique 제약조건에도 컬럼에 name이 들어가고, not null 제약조건에도 name이 들어가도 실행이 된다.

▶ 테이블을 생성할 때 2가지 방법으로 생성할 수 있다. (열 레벨 정의, 테이블 레벨 정의) -> 둘 중에 편한 거 쓰면 되지만 NOT NULL 제약조건은 무조건 열 레벨로 해야 한다.

▶ 열 레벨 정의할 때 foreign key를 꼭 쓰지 말고 바로 references 써야 하지만, 테이블 레벨 정의할 때는 foreign key(컬럼)을 써줘야 한다.

 

▶ 만약 not null 조건과 unique 조건을 합쳐서 만들고 싶을 때

create table hr.emp(
            id number,
            name varchar2(30) 
            constraint emp_name_nn not null
            constraint emp_name_uk unique, -- 열 레벨 정의
            
            sal number,
            dept_id number,
            constraint emp_id_pk primary key(id), -- 테이블 레벨 정의
            constraint emp_sal_ck check(sal between 1000 and 2000),
            constraint emp_dept_id_fk foreign key(dept_id) references 
            hr.dept(dept_id))
tablespace users;

 

drop table hr.dept purge;

출력

▶ 나를 참조하고 있는 제약조건(foreign key)이 있기 때문에 삭제 오류 발생

 

# 삭제하고 싶을 경우

 

1) 나를 참조하고 있는 제약조건을 먼저 삭제한다.

drop table hr.dept cascade constraint purge;

select * from user_constraints where table_name in ('EMP','DEPT');

▶  cascade constraint : 나를 참조하고 있는 제약조건(foreign key)을 먼저 삭제한다.

출력

 

drop table hr.emp cascade constraint purge;

select * from user_constraints where table_name in ('EMP','DEPT');

출력

 

# 테이블 다시 생성

create table hr.dept(
            dept_id number constraint dept_pk primary key,
            dept_name varchar2(30) constraint dept_name_uk unique)
tablespace users;

create table hr.emp(
            id number,
            name varchar2(30) constraint emp_name_nn not null,
            sal number,
            dept_id number,
            constraint emp_id_pk primary key(id),
            constraint emp_sal_ck check(sal between 0 and 30000),
            constraint emp_dept_id_fk foreign key(dept_id) references hr.dept(dept_id))
tablespace users;

 

■ 테이블 이름 수정

 

ex) 만약 emp 테이블을 잘못 만들었을 경우 (데이터도 있다고 가정)

select * from hr.emp;
select * from hr.dept;
desc hr.emp;

insert into hr.dept(dept_id, dept_name)
select department_id, department_name
from hr.departments;

commit;

insert into hr.emp(id, name, sal, dept_id)
select employee_id, last_name, salary, department_id
from hr.employees;

commit;

 

# 제약조건 확인

select * from user_constraints where table_name in ('EMP','DEPT');
select * from user_cons_columns where table_name in ('EMP','DEPT');
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

 

# 테이블 이름 수정 (소유자를 적으면 에러 뜬다!)

   - rename 옛날 테이블 이름 to 새로운 테이블 이름;

   - rename만큼은 소유자 이름으로 접속해야 한다.

rename emp to emp_new;
select * from hr.emp;

출력

select * from hr.emp_new;

출력

 

# 제약조건 확인할 때

select * from user_constraints where table_name in ('EMP_NEW','DEPT');
select * from user_cons_columns where table_name in ('EMP_NEW','DEPT');
select * from user_indexes where table_name in ('EMP_NEW','DEPT');
select * from user_ind_columns where table_name in ('EMP_NEW','DEPT');

 

# 테이블 수정하는 방법 2번째

   - alter table 옛날 테이블 이름 rename to 새로운 테이블 이름;

alter table emp_new rename to emp;

select * from hr.emp;

출력

select * from user_constraints where table_name in ('EMP','DEPT');
select * from user_cons_columns where table_name in ('EMP','DEPT');
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

 

■ 컬럼 이름 수정

  - alter table hr.emp rename column 옛날 컬럼 to 바꿀 컬럼 이름;

desc hr.emp;

  # ID 컬럼명을 바꾸고 싶을 경우

alter table hr.emp rename column id to emp_id;

desc hr.emp;

출력

select * from user_constraints where table_name in ('EMP','DEPT');
select * from user_cons_columns where table_name in ('EMP','DEPT');
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

▶ 업무팀에서 이름 바꿔달라고 요청서가 들어오면 하면 된다.

 

■ 제약조건 이름 수정

   - alter table hr.emp rename constraint 옛날 이름 to 바꿀 이름;

select * from user_constraints where table_name in ('EMP','DEPT');
select * from user_cons_columns where table_name in ('EMP','DEPT');
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

출력

 ex) EMP_ID_PK 이름을 수정하고 싶을 때

alter table hr.emp rename constraint emp_id_pk to emp_pk;
select * from user_constraints where table_name in ('EMP','DEPT');
select * from user_cons_columns where table_name in ('EMP','DEPT');
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

출력

 

■ 인덱스 이름 수정

   - alter index 옛날 이름 rename to 바꿀 이름;

select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

출력

 # INDEX_NAME 안에 EMP_ID_PK를 수정하고 싶을 경우

alter index emp_id_pk rename to emp_id_idx;
select * from user_indexes where table_name in ('EMP','DEPT');
select * from user_ind_columns where table_name in ('EMP','DEPT');

출력

'oracle SQL' 카테고리의 다른 글

2024.12.17 14일차 수업  (0) 2024.12.17
2024.12.12 12일차 수업  (2) 2024.12.12
2024.12.11 11일차 수업  (0) 2024.12.11
2024.12.10 10일차 수업  (2) 2024.12.10
2024.12.09 9일차 수업  (2) 2024.12.09