본문 바로가기

콩's EDUCATION/콩's DATABASE

데이터베이스 수업 5일차

p202페이지

트랜잭션 Transaction : 분리되어 수행될수 없는 논리적인 하나의 작업 단위

Unit of work

예1] 계좌이체 : A로부터 출금 - > B에게 입금 (update, update)

원자성 : 전체 작업이 완료되거나 혹은 전체 작업이 수행 전으로 취소되어야 합니다.

예2] 쇼핑몰 구매 : 결제 (결제 테이블에 insert)

구매상품, 고객정보, 배송지 주소(배송 테이블 insert)

         구매된 제품에 대한 재고 수량 변경(물품 테이블 update)

고객의 구매 history 정보 추가(고객의 구매테이블 insert)

select문 트랜잭션 처리 안함

데이터베이스는 DML문에 대해서 내부적으로 트랜잭션을 시작합니다.

트랜잭션의 종료: commit; rollback; 세션 종료(정상종료, 비정상종료), DDL, DCL문장을 수행

commit으로 종료한 경우 데이터베이스의 disk상에 변경 내용이 저장되면서 영속성을 갖는다

DDL : create, alter, drop, truncate...은 수행 즉시 auto commit됩니다.

conn hr2/hr2

select * from dept;

delete from dept; --> 내부적으로 트랜잭션 시작

select * from dept;

rollback; --> 명시적으로 트랜잭션을 종료

select * from dept;

insert into dept

values (77, 'AppDev', '경기');

select * from dept;

update dept

set loc = '대전'

where deptno = 77;

select * from dept;

command창을 새로 열고..

sqlplus hr2/hr2

select * from dept;

==> 데이터베이스에 접속한 사용자는 동일하지만 세션이 다릅니다.

==> 세션별로 트랜잭션은 격리되어서 수행됩니다.

==> 다른 세션에서의 변경은 commmit이 되어야만 다른 모든 세션에서 볼수 있다.

>>>>developer에서

commit;

select * from dept;

>>>>command창에서 hr2사용자로

select * from dept;

update emp

set sal = 0;

select * from emp;

>>>>developer에서

select sal from emp;

update emp

set sal = 1; ===>? 명령어가 완료되지 못하고 waiting됨 , 서로 다른 세션에서 동일한 데이터에 대해서 동시 변경은 불가능하도록 트랜잭션은 고립되어 수행됩니다.

>>>>command창에서 hr2사용자로

rollback;

>>>>developer에서

select sal from emp;

rollback;

drop table t_dept purge;

create table t_dept

as select * from dept

where 1=2; ===>autocommit;

insert into t_dept

select * from dept;

select * from t_dept;

==>세션을 비정상종료 합니다.

==>developer를 다시 시작시켜서 hr2로 데이터베이스에 connect

select * from t_dept;

==>세션을 비정상종료했기 때문에 진행중이던 트랜잭션은 rollback;

insert into t_dep

select * from dept;

exit; ==>세션을 정상 종료합니다.

세션을 다시 시작해서 select * from t_dept;

drop table book purge;

create table book

(isbn varchar2(10) ,

title varchar2(20),

author varchar2(20)

);

desc book;

insert into book

values (1234, 'java', 'sun micro');

savepoint a; ==> 취소할 수 있는 제어점 설정

insert into book

values (1235, 'oracle11g', 'oracle corp');

savepoint b; ==> 취소할 수 있는 제어점 설정

insert into book

values (1236, 'android', 'google');

select * from book;

rollback to a;

select * from book;

========================================

p242

emp테이블에서 전체사원의 평균 월급과

부서별 사원들의 월급의 평균과

부서별로 직무를 그룹핑한 사원들의 월급의 평균을 단일 결과로 생성하시오

select to_number(null), to_char(null), avg(sal)

from emp

union all

select deptno, to_char(null), avg(sal)

from emp

group by deptno

union all

select deptno, job, avg(sal)

from emp

group by deptno, job;

==> 각각의 select문을 실행하기 위해서 emp테이블을 3번 Access, 2번은 group by을 수행하기 위해서 hash 함수로 그룹핑 연산을 수행합니다.

select deptno, job, avg(sal)

from emp

group by rollup(deptno, job);

==>1번 대상 테이블에 Access해서 전체 그룹핑 결과와 서브 그룹핑 결과를 생성

group by rollup(A, B) => group by (A, B), group by(A), group by ()

group by rollup(A, B, C) => group by (A, B, C), group by (A, B), group by (A), group by ()

전체 그룹핑 집계와 서브그룹핑 집계를 생성

emp테이블에서 전체사원의 평균 월급과

부서별 사원들의 월급의 평균과

부서별로 직무를 그룹핑한 사원들의 월급의 평균,

직무별로만 그룹핑한 사원들의 월급의 평균을 단일 결과로 생성하시오

select to_number(null), to_char(null), avg(sal)

from emp

union all

select deptno, to_char(null), avg(sal)

from emp

group by deptno

union all

select to_number(null), job, avg(sal)

from emp

group by job

union all

select deptno, job, avg(sal)

from emp

group by deptno, job;

==>4번 테이블 Access, 3번 hash함수로 그룹핑 처리...

select deptno, job, avg(sal)

from emp

group by cube(deptno, job);

group by cube(A, B) ==> group by(A, B), group by(A), group by (B), group by ()

group by cube(A, B, C) ==> group by(A, B, C), group by(A, B), group by (B, C), group by(A, C), group by(A), group by (B), group by (C), group by ()

select deptno, job, avg(sal), grouping(deptno), grouping(job)

from emp

group by cube(deptno, job);

select deptno, job, avg(sal), , grouping(deptno), grouping(job)

from emp

group by rollup(deptno, job);

drop table 테이블 purge; ==>10g버전부터 오라클만 지원하는 옵션

==>논리적으로 테이블을 삭제하고, 테이블 이름을 rename(BIN$.....)해서 recycle bin에 남아 있으므로 조회 됨...

==>purge옵션을 주어야 recyclebin을 by pass하고 물리적으로 완전 삭제됨

drop table 테이블; 표준sql, oracle 9i까지는 물리적으로 테이블의 메타 data, 레코드가 모두 완전 삭제, 복구 불가능

drop table 테이블이름 cascade constraint;

자식테이블에서 참조하는 부모테이블은 삭제 불가이므로

삭제하려면 자식테이블에서 참조 무결성 제약조건인 foreign key를 삭제하면 부모 테이블을 삭제할 수 있습니다.

테이블에 PK, UK 제약조건이 선언된 컬럼에는 인덱스가 자동으로 생성되지만,

자주 검색에 사용되는 컬럼에 인덱스가 필요할 경우

해당 컬럼에 인덱스를 생성할 수 있습니다.

인덱스는 테이블과 따로 저장됩니다.

create index 인덱스이름 on 테이블( 컬럼 [, 컬럼,...]);

drop index 인덱스이름;

인덱스 생성해야 할 컬럼>>

where절에 자주 검색 조건으로 사용되는 컬럼

join 컬럼

group by, order by절에 자주 사용되는 컬럼

위의 후보컬럼중에서 컬럼값의 분포도가 넓은 컬럼이어야 합니다.

테이블의 row 많아서 인덱스를 사용해서 검색했을 때 전체 테이블의 2~5%이내의 행이 리턴

update등으로 컬럼값이 자주 변경되는 컬럼에는 생성하면 안됩니다.

인덱스 생성해서는 안되는 컬럼>>>

테이블의 레코드가 적은 경우

update등으로 컬럼값이 자주 변경되는 컬럼

where절,join , group by, order by절에 자주 사용되지 않는 컬럼

대상 테이블에 생성된 인덱스 정보를 조회하려면

select *

from user_indexes

where table_name = 'EMP';

View는 논리적인 테이블

table은 자신의 data가 존재하지만, View는 data가 존재하지 않습니다.

View는 테이블에 대한 window역할을 합니다.

View는 하나 이상의 테이블로부터 데이터를 조회하는 select으로 정의됩니다.

회원 ( 고객ID,주소,... )....

conn sys/oracle as sysdba

grant create view to HR2

conn HR2/HR2

create or replace view emp30_v

as select empno, ename, job, deptno

from emp

where deptno = 30;

===> alter view 구문이 없습니다.

==> 동일한 이름의 view를 생성할 경우 오류 발생하므로

==> create or replace는 존재하지 않는 view는 새로 생성하고

이미 존재하는 view에 대해서는 definition을 변경합니다.

desc emp30_v

select * from emp30_v

select *

from user_views

where view_name = 'EMP30_V';

drop view emp30_v;

==>뷰를 삭제하면 data dictionary에서 view에 대한 definition만 삭제되며

원본 테이블에는 영향을 주지 않는다.

뷰의 definition에 해당하는 select문에 group by, having, order by, 그룹함수, 수식, 조인 모두 사용 가능합니다. => 복합 뷰는 select만 가능합니다.

뷰의 definition으로 하나의 테이블, not null컬럼을 포함하는 view는 SimpleView이며, SimpleView에 insert, update, delete를 수행하면 원본 테이블에도 insert,update, delete가 수행됩니다.

시퀀스 객체 =>자동 number 생성기

게시판, 주문테이블의 경우 각각의 row를 식별할 수 있는 Primary key컬럼으로 글번호, 혹은 주문번호 컬럼을 추가합니다.

추가된 컬럼에 insert할때마다 자동으로 정수값이 증가되어 추가되도록 하려면

create sequence emp_seq;

[start with n]

[increment by n]

[maxvalue n|unlimited]

[minvalue n|unlimited]

[cycle|nocycle]

[cache|nocache]

select * from user_sequences;

시퀀스는 생성하면 자동으로 컬럼 2개 추가됩니다. nextval, currval

현재 시퀀스값 조회>>>

select emp_seq.currval from dual;

==> 에러

시퀀스 생성후 반드시 nextval먼저 호출하고 currval을 호출할 수 있습니다.

select emp_seq.nextval from dual;

select emp_seq.currval from dual;

select empno

from emp;

insert into emp (empno, ename)

values (emp_seq.nextval, '홍길동');

select empno, ename

from emp;

alter sequenece ~~;

drop sequence ~~~;

==================================================

declare

...//선언문

begin

...//실행문 (SQL문, 제어문, 반복문)

exception

...//예외처리

end;

/

p326페이지

LOOP

반복 수행 문장;

EXIT WHEN 조건 ;

END LOOP;

>>1~10사이의 홀수만 역순으로 출력하세요 BASIC LOOP

DECLARE

cnt number(2) := 10;

BEGIN

LOOP

if mod(cnt, 2) = 1 then

DBMS_OUTPUT.put_line(cnt);

end if;

cnt := cnt-1;

EXIT WHEN cnt = 0 ;

END LOOP;

END;

/

====================================================

WHILE 조건 LOOP

반복 수행 문장;

END LOOP;

>> 1~10까지의 누적합을 구하시오

DECLARE

cnt number(2) := 1;

hap number(2) := 0;

BEGIN

WHILE cnt <= 10 LOOP

hap := hap+cnt;

cnt := cnt+1;

END LOOP;

DBMS_OUTPUT.put_line('1~10까지의 누적합은 '||hap);

END;

/

FOR 카운트 변수 IN 하한값..상한값 LOOP

반복 수행 문장;

END LOOP;

FOR 카운트 변수 IN REVERSE 하한값..상한값 LOOP

반복 수행 문장;

END LOOP;

>>1~10사이의 짝수를 역순으로 출력하시오 (FOR LOOP문 사용)

BEGIN

FOR cnt IN REVERSE 1..10 LOOP

if mod(cnt , 2) = 0 then

dbms_output.put_line(cnt);

end if;

END LOOP;

end;

/

>>구구단 7단 출력하시오 (FOR LOOP문 사용)

BEGIN

FOR i IN 1..1 LOOP

dbms_output.put_line(7 || '*'|| i ||'='||(7*i));

END LOOP;

end;

/

>>구구단 출력하시오 (FOR LOOP문 사용)

BEGIN

FOR i IN 1..9 LOOP

FOR j IN 2..9 LOOP

dbms_output.put(j || ' * '|| i ||' = '||(j*i)||' ');

END LOOP;

dbms_output.new_line();

end loop;

end;

/

create or replace procedure 프로시저이름 (num in|out|inout number, ..)

[is]

로컬변수;//

begin

실행문장;

exception

예외처리 문장

end 프로시저이름;

/

create table patient(

patient_id varchar2(6)

, body_temp_deg_c number(4, 1)

, body_temp_deg_f number(4,1)

, insurance varchar2(1)

);

select * from patient;

create or replace procedure changeCF(patientId in varchar2, temp_c binary_double)

is

temp_f binary_double := 0.0 ;

begin

temp_f := (9.0/5.0)* temp_c +32.0;

insert into patient ( patient_id, body_temp_deg_c , body_temp_deg_f)

values (patientId, temp_c, temp_f);

end;

/

execute changeCF ('YN0001', 40.0)

execute changeCF('YN0002', 41.0)

select * from patient;

=================================================================

conn hr2/hr2

drop table t_emp purge;

create table t_emp

( deptno number(4),

sum_sal number(8, 2),

avg_sal number(8, 2),

avg_tax number(8, 2),

avg_comm number(8, 2)

);

>>부서번호를 입력받으면 해당 부서번호 소속 사원의 월급합계, 월급 평균,

커미션 평균, 평균 세금을 계산해서 t_emp테이블에 insert를 수행하는 프로시저를 만드세요..

커미션이 없으면 0으로 처리합니다.

세금은 부서별 평균이 1000이상이면 5%, 2000이상이면 10% , 3000이상이면 15%, 4000이상이면 20%로 계산합니다.

create or replace procedure dept_all_avg(p_deptno number)

is

v_sum_sal emp.sal%type :=0;

v_avg_sal emp.sal%type :=0;

v_avg_comm emp.comm%type :=0;

v_avg_tax emp.sal%type :=0;

begin

select sum(sal), avg(sal) , avg(nvl(comm, 0))

into v_sum_sal, v_avg_sal, v_avg_comm

from emp

where deptno = p_deptno;

v_avg_tax := case when v_avg_sal > 1000 then v_avg_sal*0.05

when v_avg_sal > 2000 then v_avg_sal*0.1

         when v_avg_sal > 3000 then v_avg_sal*0.15

         when v_avg_sal > 4000 then v_avg_sal*0.2

         end ;

insert into t_emp (deptno,sum_sal , avg_sal, avg_tax, avg_comm )

values (p_deptno, v_sum_sal, v_avg_sal, v_avg_tax, v_avg_comm);

end;

/

execute dept_all_avg(10)

execute dept_all_avg(30)

select * from t_emp;

함수 : 반드시 하나의 값을 리턴

create or replace function 함수이름 (파라미터...)

return 리턴타입

is

로컬 변수 선언 및 초기화

begin

실행문장;

return 값;

end;

/

>>사원번호를 입력 받아서 해당 사원의 세금을 계산리턴

월급이 1000이상이면 5%, 2000이상이면 10% , 3000이상이면 15%, 4000이상이면 20%로 계산합니다.

create or replace function emp_tax(p_empno number)

return number

is

v_tax emp.sal%type := 0;

v_sal emp.sal%type := 0;

begin

select sal into v_sal

from emp

where empno = p_empno;

v_tax := case when v_sal > 4000 then v_sal*0.2

when v_sal > 3000 then v_sal*0.15

         when v_sal > 2000 then v_sal*0.1

when v_sal > 1000 then v_sal*0.05    

end ;

return v_tax;

end;

/

select empno, sal, emp_tax(empno)

from emp;

conn scott/tiger

create or replace function member_sex (p_registno varchar2)

return varchar2

is

v_sex varchar2(10) := '남자';

v_substr char(1) := '0';

begin

select substr(regist_no, 8, 1) into v_substr

from ec_member

where regist_no = p_registrno;

if v_substr = '2' then v_sex := '여자'

end if;

return v_sex;

end;

/

select userid, name, regist_no, member_sex(regist_no) "성별"

from ec_member;

create or replace function member_yymm (p_userid ec_member.userid%type)

return varchar2

is

v_duration varchar2(15) ;

v_year number(2) :=0;

v_month number(3) := 0;

begin

select ceil(ceil(months_between(sysdate, timestamp))/12) ,

mod(ceil(months_between(sysdate, timestamp)), 12)

into v_year, v_month

from ec_member

where userid = p_userid;

v_duration := v_year ||'년 '||v_month||'개월';

return v_duration;

end;

/

select userid, name, timestamp, member_yymm(userid) "가입기간"

from ec_member;