This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
sqlplus scott/tiger 접근이 안될경우 주로 Lock이 걸려 있을 경우 이므로 Lock 을 해제해 주어야 합니다.
DBA 계정으로 접근 sqlplus system/비밀번호
alter user scott account unlock;
connect scott/tiger
사용자 초기암호를 변경하지 않으려면 sqlplus system/change_on_install 을 실행시켜주면 됩니다.
1. SQL
데이터 질의어(DQL, Data Query Language) SELECT (데이터 검색)
데이터 정의어(DDL, Data Definition Language) 객체생성및 변경 CREATE (객체 생성) ALTER (객체 변경) DROP (객체 삭제) RENAME (객체이름 변경) TRUNCATE (객체의 저장 공간 삭제)
데이터 조작어(DML, Data Manipulation Language) INSERT (데이터 입력) UPDATE (데이터 수정) DELETE (데이터 삭제)
데이터 제어어(DCL, Data Control Language) GRANT (데이터베이스에 대한 일련의 권한 부여) REVOKE (데이터베이스에 대한 일련의 권한 취소)
트랜잭션 처리어(TCL, Transaction Control Language) COMMIT (트랜잭선의 정상적인 종료처리) ROLLBACK (트랜잭션 취소) SAVEPOINT (트랜잭션내에 임시 저장점 설정)
데이터베이스 사용자 사용자 - 데이터베이스 관리자, 응용프로그래머, 최종 사용자
DBMS(DataBase Management System) 데이터베이스 관리자 - 자료 정의, 저장 관리 응용프로그래머, 최종 사용자 - 질의 처리, 트랜잭션 관리
저장장치 데이터베이스 관리자 - 데이터 딕셔너리 응용프로그래머, 최종 사용자 - 데이터베이스
2. sql 시작
모든 테이블 목록 확인하기 select * from tab;
테이블 구조 보기 desc salgrade;
특정 테이블의 데이터 보기 select * from emp;
특정 데이터에 문자열을 더하고 싶을때 select ename || ' is a ' || job from emp; 결과 : tiger is a killer
중복 데이터 제거 select distinct deptno from emp;
NULL 값을 임시 특정 문자로 보여주기 set NULL "널값"; 복구 하려면 set NULL "";
3. 오라클 데이터형
1) NUMBER
NUMBER(precision, scale)
precision : 전체 자리수 scale : 소수점 이하 자리수, 생략하면 NUMBER(precision) 정수만 표현되며, 소수점이하는 반올림됨.
12345 NUMBER(5) 123456.78 NUMBER(8, 2)
2) DATE 기본 날짜 형식 - YY/MM/DD 년/월/일 09/08/19 2009년/08월/19일 영문판 날짜 형식 - DD/MON/YY 일/월/년 19/Aug/09 19일/8월/2009년
3) VARCHAR2 가변적인 길이의 문자열을 저장하기 위한 자료형 CHAR 형은 주어진 공간에 모자르게 입력되더라도 나머지 공간이 남아 있게 되므로 낭비가 발생하지만, VARCHAR2 는 주어진 공간안에 입력된 자료형 만큼만 할당됩니다.
VARCHAR2(20) 실제 입력 문자열 "test" 이면 20자리중 4자리만 사용하므로 나머지 16자리는 자동 할당되지 않습니다.
SQL문은 Relation 이라 불리는 테이블을 저장 단위로 생각하는 RDB(Relational DataBase)에서 저장, 수정, 삭제, 추출을 위해 미국표준협회(ANSI)에서 표준으로 채택한 언어인 반면 SQL Plus
명령어는 오라클사가 그러한 SQL문을 사용자가 데이터베이스에 입력하고 그 결과를 받을 수 있도록 만든 툴입니다.
1. SQL과 SQL Plus 비교
SQL 문 SQL Plus 명령문 관계형 데이터베이스의 ANSI 표준언어 SQL문을 실행시킬 수 있는 오라클의 툴여러 줄 실행 한줄 실행종결문자(;) 필요 종결문자 불필요연결문자 불필요 연결문자(-) 필요키워드 단축 불가 키워드 단축 가능버퍼에 마지막 명령문 저장 버퍼 저장 안함
2. 주로 사용되는 명령어
LIST, SAVE, GET, EDIT, SPOOL 편집 명령과 파일 조작RUN, @, / 실행HOST, EXIT 데이터베이스 접속 및 종료LINE, PAGE 출력 형식
1) LIST
SELECT ename, sal*12 FROM emp;
LIST 방금 실행한 쿼리문을 다시한번 보여줍니다. L 이라고 단축으로 실행하셔도 됩니다.
2) RUNLIST로 버퍼에 저장된 쿼리문을 실행하기 위한 명령어입니다.RUN은 R 이나 / (슬레시)로 단축키를 사용할 수 있습니다.
3) EDIT 버퍼에 저장된 쿼리문을 편집하기 위한 명령어 EDIT 는 ED 라는 단축키를 사용할 수 있습니다.
편집창이 호출되고 명령문을 편집완료하였다면 창을 닫으면 저장할지 여부를 묻습니다.저장하게 되면 SQL Plus 화면에 편집된 쿼리문을 보여줍니다.실행하시려면 R 이나 / 를 입력하시면 됩니다.
4) HOST 도스 프롬프트로 나가서 다른 작업을 수행할 수 있습니다.완전히 종료되는 것은 아니고 일시적으로 수행창을 도스 프롬프트로 바꾸어 줍니다.다시 SQL Plus로 돌아가려면 도스 프롬프트 창을 닫으시면 됩니다.
5) EXIT SQL Plus 를 완전히 종료합니다.
6) SAVE 마지막에 실행한 명령어를 저장하는 명령어입니다. SAVE a001
a001.sql 이 생성됩니다.
저장된 파일을 실행하려면 @a001 처럼 @기호와 파일이름을 써주고 엔터키를 누르면 됩니다.
저장된 파일에 새로운 결과를 저장하려면
select * from dept; 라는 명령문을 실행했다고 본다면
SAVE a001 REPLACE 를 실행합니다.
결과를 다시 확인하려면 불러들이면 되죠... @a001
7) GET 파일로 저장된 쿼리문을 불러와서 보여줍니다. 실행은 R 이나 / 기호를 이용하여야 합니다.
8) SPOOL SPOOL b001 b001 로 실행결과를 저장하겠다는 표현이며, select * from emp; select * from dept; 의 실행 결과를 최종 저장하기 위해선SPOOL OFF 가 최종 실행되어야 합니다.
HOST로 잠시 도스프롬프트창으로 나가서 dir *.lst 를 실행하시면 결과파일이 생성됨을 보실 수 있습니다.
notepad b001.lst
exit다시 돌아옵니다.
9) 시스템 변수 설정하기 위한 SET 명령어
형식: SET 시스템_변수명 값
SET HEADING OFF
select * from emp; 컬럼제목이 나오지 않게 합니다
SET HEADING ON
select * from emp; 다시 복원 합니다.
10) 한 화면에 출력되는 라인의 수를 결정하는 LINESIZE 변수
SET LINESIZE 40 desc emp;
11) 한 페이지에 출력되는 페이지의 크기를 결정하는 PAGESIZE 변수 SET PAGESIZE 10 select * from emp;
12) 컬럼제목을 설정하기 위한 COLUMN HEADING COLUMN empno HEADING '사원번호' select * from emp;
13) 컬럼에 대한 설정된 값을 확인하거나 해제하기 확인: COLUMN empno
해제: COLUMN empno CLEAR
14) 컬럼 제목의 출력 형식을 변경하기 위한 COLUMN FORMAT
COLUMN dname FORMAT A10 해당 컬럼의 크기를 10으로 지정합니다.
숫자 데이터 출력형식 변경 COLUMN sal FORMAT 0,000,000
숫자의 경우 다시 복원하려면 COLUMN dname FORMAT 999999
1) 날짜형
select ename, hiredate from emp where hiredate >= '82-01-01';
미국식일 경우 select ename, hiredate from emp where hiredate >= '01-MAR-01';
2) 와일드 카드(_)를 사용하기 select empno, ename from emp where ename like '_A%'; 제일 앞문자가 무엇이든지 두번째 문자는 반드시 A를 포함한 검색식 입니다.
3) ESCAPE ESCAPE 뒤에 오는 단 한글자의 와일드 카드문자를 와일드 카드가 아닌 문자 그대로 인식시키도록 합니다.
select empno, ename from emp where ename like '%\%%' ESCAPE '\';
\ 다음의 문자를 그대로 인식 시키게 하는 옵션 입니다.
4) IN 연산자 select empno, ename, comm from emp where comm IN (300, 400, 500); comm(커미션)이 300, 400, 500 인 사람을 검색 합니다.
5) BETWEEN AND 연산자 select empno, ename, sal from emp where sal BETWEEN 500 AND 4000; 500 과 4000 사이의 급여대상자 검색식. 500 과 4000 도 범위에 들어갑니다.
일반 식으로는 sal >= 500 AND sal <= 4000 이 됩니다.
6) 논리 연산자 AND OR NOT
AND 와 OR 연산자는 많이 알려진 연산자로 둘다 참이 거나 거짓일 경우와 둘중에 하나만 참이거나 거짓일 경우를 가려내기 위핸 연산자입니다.
select empno, ename, comm from emp where comm NOT IN (300, 400, 500); comm(커미션)이 300, 400, 500 이 모두 아닌 사람을 검색 합니다.
NOT 연산자는 NOT IN 이외에도 NOT like NOT BETWEEN A AND B IS NOT NULL ( <> IS NULL)
1. DUAL 테이블 select 10*20 from dual;
산술 연산이나 가상 컬럼 등의 값을 한번만 출력하고 싶을때 많이 사용하는 아주 유용한 테이블입니다.
2. 숫자 함수 숫자 데이터를 처리하기 위한 함수.
1) ROUND(반올림) 함수
select round(45.293, 2) from dual; 결과 : 45.29 소수점에서 2 지점은 . 에서 오른편을 말합니다. 즉, 3가 대상이 됩니다. 3은 반올림 대상 숫자가 아니므로 9는 변하지 않습니다.
select round(45.293, 1) from dual; 결과 : 45.3 소숫점에서 1 지점은 . 에서 오른편을 말합니다. 즉, 9가 대상이 됩니다. 9는 반올림 대상 숫자이므로 2가 3으로 반올림되었습니다.
select round(45.293, 0) from dual; 결과 : 45 소수점에서 0지점은 . 에서 오른편을 말합니다. 즉, 2가 대상이 됩니다. 2는 반올림 대상 숫자가 아니므로 45는 변하지 않습니다.
select round(45.293, -1) from daul; 결과 : 50 소숫점에서 -1 지점은 . 에서 왼편을 말합니다. 즉, 5가 대상이 됩니다. 5는 반올림 대상 숫자이므로 45 에서 50으로 변경되었습니다.
2) TRUNC(버림) 함수 select trunc(45.196, 2) from dual;
결과 : 45.19 소숫점에서 2 지점은 . 에서 오픈편을 말합니다. 즉, 6이 대상이됩니다.
3) MOD(나머지 구하는) 함수 select sal, mod(sal, 100) from emp;
select * from emp where mod(empno, 2) = 1;
3, 문자 처리 함수 1) UPPER 대문자로 변환시킨다.
select upper('aBcD') from dual;
2) LOWER 소문자로 변환시킨다.
select lower('aBcD') from dual;
3) INITCAP 이니셜만 대문자로 변환시킨다.
select initcap('Welcome to Oracle 10g') from dual; 결과 : Welcome To Oracle 10g
select initcap(ename) from emp; 결과 : 영문 이름의 제일 앞자만 대문자로 변환됨.
4) LENGTH 문자열의 길이를 알려준다.
select length('Welcome to Oracle 10g') from dual; 결과 : 21
5) INSTR 특정문자가 출현하는 위치를 알려준다.
select instr('Welcome to Oracle 10g', 'o', 3, 2) from dual; 결과 : 10
영소문자 'o' 를 찾기 위해 3번째 문자열 부터 시작해서 'o' 문자를 찾은 두번째의 위치의 자리수를 구함. 3번째 자리 부터 : 'l' 첫번째 'o' 의 위치 : 5 두번째 'o' 의 위치 : 10
select ename, instr(ename, 'A') from emp; 이름에 'A' 자가 몇 번째에 위치하는지 출력.
6) SUBSTR 문자의 일부분을 추출한다.
select substr('Welcome to Oracle 10g', 4, 3) from dual;
네번째 문자 'c' 부터 3개 문자인 'com' 을 추출한다.
select substr('Welcome', -3, 2) from dual; 오른쪽에서 세번째 문자 'o' 부터 2개 문자인 'om' 을 추출한다.
7) LPAD 오른쪽 정렬 후 왼쪽에 생긴 빈 공백에 특정 문자를 채운다.
select lpad('Oracle 10g', 20, '#') from dual; 결과 : ##########Oracle#10g lpad는 기호 문자가 왼쪽에 채워집니다.
8) RPAD 왼쪽 정렬 후 오른쪽에 생긴 빈 공백에 특정 문자를 채운다.
select rpad('Oracle 10g', 20, '#') from dual; 결과 : Oracle#10g########## rpad는 기호 문자가 오론쪽으로 채워집니다.
9) LTRIM 왼쪽에서 특정 문자를 삭제한다.
select ltrim('aaaOracle 10gaaa', 'a') from dual; 결과 : Oracle 10gaaa
select ltrim(' Oracle 10g ') from dual; 결과 : Oracle 10g 문자열 왼쪽만 삭제됨.
10) RTRIM 오른쪽에서 특정 문자를 삭제한다.
select rtrim('aaaOracle 10gaaa', 'a') from dual; 결과 : aaaOracle 10g
select rtrim(' Oracle 10g ') from dual; 결과 : Oracle 10g문자열 오른쪽만 삭제됨.
11) TRIM 앞뒤에서특정 문자를 삭제한다.
select ename, trim('A' from ename) from emp;
select trim('A' from 'AaaaA') from dual; 결과 : aaa
12) BETWEEN A AND B
select hiredate from emp where hiredate between '17-DEC-80' and '09-JUN-99';
4. 날짜 관련 함수 날짜 데니터 타입에 사용되는 함수.
1) 날짜 연산 SYSDATE + 1 내일 날짜를 구함
SYSDATE - 1 어제 날짜를 구함
select sysdate + 1 from dual; select sysdate - 1 from dual;
직원들의 현재까지 근무 일수를 구하는 쿼리문 select ename, hiredate, sysdate - hiredate from emp;
2) MONTHS_BETWEEN 날짜와 날짜 사이의 개월을 계산한다. (숫자 반환)
select sysdate, hiredate, months_between(sysdate, hiredate) from emp;
3) ADD_MONTHS 날짜에 개월을 더한 날짜 계산 (날짜 반환)
select hiredate, add_months(hiredate, 6) from emp;
4) NEXT_DAY 날짜 후의 첫 요일의 날짜 계산 (날짜 반환)
영문일 경우
입사일 기준 최초로 도래하는 금요일 검색 select hiredate, next_day(hiredate, 'fri') from emp;
오늘이 속한 달의 마지막 날짜와 다가오는 금요일의 날짜를 검색 select sysdate, last_day(sysdate), next_day(sysdate, 'fri') from dual;
입사 후 6개월이 지난 후 돌아오는 금요일의 날짜를 검색 select hiredate, add_months(hiredate, 6) from emp; select next_day(add_moths(hiredate, 6), 'fri') from emp;
한글일 경우 select hiredate, next_day(hiredate, '금') from emp; 한글이 인식 안될 경우 alter session set NLS_LANGUAGE=K016KSC5601;
select sysdate, last_day(sysdate), next_day(sysdate, '금') from dual;
select hiredate, add_months(hiredate, 6) from emp; select next_day(add_moths(hiredate, 6), '금') from emp;
5) LAST_DAY 월의 마지막 날짜를 계산 (날짜 반환) select hiredate, last_day(hiredate) from emp;
6) ROUND 날짜를 반올림 (날짜 반환)
7) TRUNC 날짜를 절삭 ( 날짜 반환)
8) SYSDATE 함수 시스템에 저장된 현재 날짜를 반환하는 함수. (숫자 반환)
select sysdate from dual;
5. 형 변환 함수
1) TO_DATE 문자열을 날짜 형으로 변환하는 함수
TO_DATE('문자열', 'format')
select sysdate - to_date('2006/01/01', 'YYYY/MM/DD') from dual; 현재 날짜에서 2006/01/01을 뺀 결과 검색
2) TO_CHAR 날짜나 숫자를문자로 변환하는 함수
TO_CHAR(number | date, 'format')
format의 종류
YYYY 년도 표현(4자리) YY 년도 표현(2자리) MM 월을 숫자로 표현 MON 월을 알파뱃으로 표현 DAY 요일 표현 DY 요일을 약어로 표현
시간 출력 형식의 종류
AM, PM 오전(AM), 오후(PM) 시각 표시 HH, HH12 시간(1 ~ 12) HH24 24시간으로 표현(0 ~ 23) MI 분 표현 SS 초 표현
select to_char(sysdate, 'YYYY/MM/DD, HH24:MI:SS') from dual; 현재 날짜와 시간을 출력
select to_char(sysdate + 2/24, 'yyyy-mm-dd hh:mi:ss') from dual; 현재 시간에 3시간을 더하여 검색
숫자 관련 출력 형식
9 한자리의 숫자 표현 예: (1111, '99999') 결과:1111 0 앞부분을 0으로표현 예: (1111, '099999') 결과:001111 $ 달러기호를 앞에 표현 예: (1111, '$99999') 결과:$1111 . 소수점 표현 예: (1111, '99999.99') 결과:1111.00 , 특정 위치에 , 표시 예: (1111, '99,999') 결과:1,111 MI 오른쪽에 -기호 표시 예: (1111, '99999MI) 결과:1111-
PR 음수값을 <>으로 표현 예: (1111, '99999PR) 결과:<1111> EEEE 과학적표기법으로 표현 예: (1111, '9.999EEEE') 결과:1.111E+03 V 10^n을 곱한 값으로 표현 예: (1111, '999V99') 결과:111100 B 공백을 0으로 표현 예: (1111, 'B9999.99') 결과:1111.00 L 지역 통화(Local currency) 예: (1111, 'L99999') 결과:\1111
select ename, TO_CHAR(sal, '$999,999') from emp;
select ename, TO_CHAR(sal, 'L999,999') from emp;
3) NULL 변환 함수인 NVL NULL을 0 또는 다른 값으로 변환하기 위해서 사용하는 함수.
select ename, sal, comm, sal*12+NVL(comm, 0) from emp; 커미션이 null경우 0으로 변경하여 연봉계산에 함산하는 검색식
select ename, NVL(TO_CHAR(mgr, '9999'), 'CEO') from emp; 상관(manager)가 없는 mgr 컬럼값을 문자형 데이터로 형변화해서 CEO 표현하는 검색식
select ename, job, DECODE(job, 'CLERK', sal*1.05, 'MANAGER', sal*.1.15, sal) as "Up Sal" from emp;
직급에 따라 보너를 지급하기 위한 조건식
직급이 MANAGER인 사원은 15% 인상하고, CLERK인 사원은 5% 인상합니다.
5) 조건에 따라 서로 다른 처리가 가능한 CASE 함수
select ename, deptno, CASE WHEN deptno=10 THEN 'ACCOUNTING' WHEN deptno=20 THEN 'RESEARCH' WHEN deptno=30 THEN 'SALES' WHEN deptno=40 THEN 'OPERATIONS' END AS dname from emp;
select job, sal, CASE WHEN job='CLERK' THEN sal*1.20 WHEN job='ANALYST' THEN sal*1.15 WHEN job='MANAGER' THEN sal*1.10 ELSE sal END AS salary
select max(ename), min(ename), max(hiredate), min(hiredate) from emp;
6. GROUP BY 절 select avg(sal) from emp group by deptno;
select deptno, avg(sal) from emp group by deptno; 부서별로 급여 사항이 출력
select deptno, ename, avg(sal) from emp group by deptno; 오류: ename 은 group by 절에 선언되지 않은 컬럼입니다. sal의 경우 그룹함수를 이용하므로 오류를 발생하지 않습니다.
select deptno, count(*), count(comm) from emp grou by deptno;
부서별 전체 사원수와 커미션을 받는 사원들의 수 계산
select deptno, max(sal), min(sal) from emp group by deptno; 부서별 최대 급여와 최소 급여 산출
7. HAVING 절 GROUP BY 절에 의해 생성된 결과 값 중 원하는 조건에 부합하는 자료만 보고자 할 때 사용합니다.
select deptno, avg(sal) from emp group by deptno having avg(sal) >= 2000; 부서별로 평균을 구하되 평균값이 2000 이상인 자료만 산출
select empno, ename, deptno from emp where empno=7900;
select dname from dept where deptno=30;
1. EQUI JOIN 조인 대상이 되는 두 테이블에서 공통적으로 존재하는 컬럼의 값이 일치되는 행을 연결하여 결과를 생성하는 조인 방법.
select ename, dname from emp, dept where emp.deptno=dept.deptno;
select ename, dname, emp.deptno, dept.deptno from emp, dept where emp.deptno=dept.deptno;
select e.name, d.dname, e.deptno, d.deptno from emp e, dept d where e.deptno=d.deptno;
select ename, dname from emp, dept where emp.deptno=dept.deptno and emp.ename='SCOTT';
2. NON-EQUI JOIN 조인 조건에 특정 범위 내에 있는지를 조사히기 위해 where 절에 조인 조건을 = 연산자 이외의 비교 연산자를 사용합니다.
select e.ename, e.sal, s.grade from emp e, salgrade s where e.sal >= s.losal and e.sal <= s.hisal; 급여등급을 5개로 나누어 좋은 salgrade에서 정보를 얻어 와서 각 사원의 급여 등급을 지정하는 쿼리
select e.ename, e.sal, s.grade from emp e, salgrade s where e.sal between s.losal and s.hisal; 위의 쿼리를 BETWEEN A AND B 형식으로 수정한 쿼리문
select e.ename, d.dname, s.grade from emp e, dept d, salgrade s where e.deptno = d.deptno and e.sal between s.losal and s.hisal;
3. SELF JOIN 같은 테이블이지만 별칭으로 다른 테이블을 조인하는 형식을 사용합니다.
select ename, mgr from emp;
select e.ename || '의 매니저는 ' || m.ename || '입니다.' from emp e, emp m where e.mgr=m.empno;
위의 쿼리문은 from 절로 봐서는 SELF JOIN 이고, where 절로 봐서는 EQUI JOIN에도 속합니다.
4. OUTER JOIN 사원번호가 NULL 인 사원이 존재할때 조인조건에 만족하지 못할때, 결과에서 배제되는 경우를 해결하기 위해 해당 행을 나타내고 싶을때 사용합니다. (+) 연산자를 사용하여 NULL값이기에 배제된 행을 결과에 포함시킬수 있습니다.
select e.ename || ' 의 매니저는 ' || m.ename || '입니다.' from emp e, emp m where e.mgr=m.empno(+);
select e.ename, d.dname from emp e, dept d where e.deptno(+) = d.deptno;
부서번호가 없어도 출력하는 쿼리
select e.ename, d.deptno, d.dname from emp e, dept d where e.deptno=d.deptno;
select e.ename, e.job, e.deptno, d.loc from emp e, dept d where e.deptno=d.deptno and e.deptno=30;
부서번호 30인 사원들을 출력하는 쿼리문
select e.ename, e.comm, d.dname, d.loc from emp e, dtpt d where e.detpno=d.deptno and e.comm IS NOT NULL and e.comm NOT IN (0);
커미션을 받는 사원을 출력하는 쿼리문
select e.ename, e.job, d.deptno, d.dname from emp e, dept d where e.deptno=d.deptno and d.loc='DALLAS';
DALLAS에서 근무하는 사원을 출력하는 쿼리문
select e.ename, d.dname from emp e, dept d where e.deptno=d.deptno and e.ename like '%A%';
이름에 A가 들어가는 사원들을 출력하는 쿼리문
select e.ename, e.job, e.sal, s.grade from emp e, salgrade s where e.sal between s.losal and s.hisal;
사원이름, 직급, 급여, 급여등급 출력 쿼리
select e.ename "자신", e.deptno, c.ename "동료", c.deptno from emp e, emp c where e.ename <> c.ename and e.deptno=c.deptno order by e.ename;
SELF JOIN 사원이름, 부서번호와 해당 사원과 같은 부서에서 근무하는 사원을 출력하는 쿼리
하나의 테이블에서 검색한 결과를 다른 테이블에 전달하여 새로운 결과를 검색하는 경우에 사용합니다.
[서브 쿼리의 예]
select dname from dept where deptno=20; select ename, deptno from emp where ename='JONES';
select dname from dept where depto=(select deptno from emp where ename='JONES');
1. 단일 행 서브 쿼리
하나의 행만 검색하여 그 결과를 메인 쿼리에 보내는 쿼리. 위의 JONES의 부서명을 구하는 예가 단일 행 서브 쿼리입니다.
select e.ename, d.dname from emp e, dept d where e.deptno=d.deptno and d.deptno=10
emp 테이블의 결과는 세개 입니다. 위의 경우는 EQUI JOIN 문을 이용한 예입니다.
select e.name, d.dname from emp e, ( select deptno, dname from dept where deptno=10 ) d where e.deptno=d.deptno;
같은 결과를 낼수 있는 방법중 서브쿼리를 이용하는 방법입니다.
2. 서브 쿼리에서 그룹 함수의 사용
select avg(sal) from emp; 평균 급여 구하는 쿼리
select ename, sal from emp where sal > (select avg(sal) from emp); 평균 급여보다 더 많은 급여를 받는 사원을 검색하는 쿼리
select ename, sal from emp where sal > (select avg(sal) from emp) order by sal desc; 많이 받는 사람 순으로 출력 쿼리
select empno, ename from emp where sal = ( select max(sal) from emp where deptno=10 );
부서번호가 10인 사원중에서 최대 급여를 받는 사원과 동일한 급여를 받는 사원 번호와 사원명 출력
3. 다중 행 서브 쿼리 다중 행 연산자(Multiple Row Operator)와 함께 사용하여 하는 서브 쿼리.
IN 메인 쿼리의 비교 조건이 서브 쿼리의 결과 중에서 하나라도 일치하면 참입니다. ANY, SOME 메인 쿼리의 비교 조건이 서브 쿼리의 결과와 하나 이상 일치하면 참입니다. ALL 메인 쿼리의 비교 조건이 서브 쿼리의 결과와 모든 값이 일치하면 참입니다. EXIST 메인 쿼리의 비교 조건이 서브 쿼리의 결과 중에서 만족하는 값이 하나라도 존재하면 참입니다.
1) IN 연산자
select deptno from emp where ename = 'BLAKE';
select ename, hiredate, deptno from emp where deptno IN ( select deptno from emp where ename='BLAKE');
BLAKE의 결과값중 부서번호가 30인 사람들까지 같이 출력 됩니다.
select ename, hiredate from dept where deptno IN ( select deptno from emp where ename='BLAKE'); and ename != 'BLAKE'
BLAKE 는 제외하고 출력하는 쿼리
select distinct deptno from emp where sal >= 3000;
급여를 3000 이상 받는 사원이 소속된 부서번호는 10번 20번 입니다.
select ename, sal, deptno from emp where deptno = 10 or deptno = 20; 10, 20번 부서의 이름, 급여, 부서번호를 출력하는 쿼리
위의 검색 조건을 합칠 경우 다음과 같은 서브 쿼리문을 사용하게 됩니다. select ename, sal, deptno from emp where deptno IN ( select deptno from emp where sal >= 3000 );
3000 이상받는 직원과 관련된 부서의 직원들을 출력 합니다.
2) ALL 연산자
select sal from emp where deptno=30; 부서번호가 30 인 사원들을 출력 합니다. 가장많은 급여는 2850 입니다.
select ename, sal from emp where sal > ALL( select sal from emp where deptno = 30 );
30번 부서에서 급여를 가장 많이 받는 사원의 급여인 2850보다 더 높은 급여를 받는 사원들만 출력. 즉, 전체 결과에서 30번 부서에서 가장 높은 급여보다 많이 받는 사람을 구하는 겁니다.
30번 부서의 급여 최대치 2850 과 비교 될때까지 연산하는 것이 ALL 연산자 입니다.
> ALL은 "모두다 크냐"고 묻는 것이 되므로 최대값보다 더 크면 참이 됩니다.
3) ANY 연산자 > ANY 는 "비교값 중 하나보다 크냐"고 묻는 것이 되므로 그 값들 중 어느 하나 보다 더 크면, 값들 중 최소값보다 더 크면 참이 됩니다.
select ename, sal from emp where sal > ANY ( select sal from emp where deptno = 30 );
4) 싱글과 멀티
싱글은 =, >, >=, <, <=, != 등 연산자만 사용 멀티는 IN, ALL, ANY, SOME, EXIST 사용
4. 예제 1) SCOTT의 급여와 동일하거나 더 많이 받는 사원명과 급여를 출력 select ename, sal from emp where sal >= ( select sal from emp where ename='SCOTT' );
2) 직급(job)이 사원(CLERK)인 사람의 부서를 검색 select distinct deptno from emp where job='CLERK';
직급(job)이 사원(CLERK)인 사람의 부서의 부서 번호와 부서명과 지역을 출력
select deptno, dname, loc from dept where deptno IN ( select deptno from emp where job='CLERK' );
3) 이름에 T를 포함하고 있는 사람들과 같은 부서에 근무하고 있는 사원의 사원번호와 이름을 출력 select distinct deptno from emp where ename like '%T%'; 먼저 T자가 포함된 부서번호를 구합니다.
select empno, ename from emp where deptno IN ( select deptno from emp where ename like '%T%' );
4) 부서 위치가 dallas 인 모든 사원의 이름, 부서 번호를 출력 select ename, deptno from emp where deptno = ( select deptno from dept where loc='DALLAS' );
5) SALES 부서의 모든 사원과 이름과 급여를 출력 select ename, sal from emp where deptno = ( select deptno from dept where dname='SALES' );
6) KING 에게 보고하는 모든 사원의 이름과 급여를 출력 KING이 매니져(mgr)라는 의미.
select ename, sal from emp where mgr IN ( select empno from emp where ename='KING' );
7) 자신의 급여가 평균 급여보다 많고 이름에 S가 들어가는 사원과 동일한 부서에서 근무하는 모든 사원의 이름, 급여를 출력
select empno, ename, sal from emp where deptno IN ( select deptno from emp where sal > ( select avg(sal) from emp ) and ename like '%S%' );
1. 테이블 생성 CREATE TABLE 테이블명 ( 컬럼명 자료형 )
[오라클 자료형]
CHAR(N) 주어진 크기만큼 고정 길이의 문자 저장. 1바이트~2000바이트 VARHCAR2(N) 주어진 크기만큼 가변 길이의 문자 저장. 1바이트~4000바이트 NVARCHAR2(N) 국가별 국가 집합에 따른 크기의 문자 또는 바이트의 가변 길이 문자. 1바이트~4000바이트 NUMBER(P, S) 정밀도와 스케일로 표현되는 숫자 DATE 날짜 형식을 지정 ROWID 테이블내 행의 고유 주소를 가지는 64진수 문자. 해당 6바이트(제한된 ROWID)
또는 10바이트(확장된 ROWID) BLOB 대용량의 바이너리 데이터를 저장, 최대 4GB CLOB 대용량의 텍스트 데이터를 저장, 최대 4GB BFILE 대용량의 바이너리 데이터를 파일 형태로 저장, 최대 4GB TIMESTAMP(n) DATE형의 확장된 형태 INTERVAL YEAR TO MONTH 년과 월을 이용하여 기간을 저장 INTERVAL DAY TO SECOND 일, 시, 분, 초를 이용하여 기간을 저장, 두 날짜 값의 정확한 차이를 표현하는데 유용.
1) INTERVAL YEAR TO MONTH
INTERVAL YEAR(년도에 대한 자리수) TO MONTH(달에 대한 자리수) 자리수를 지정하지 않으면 기본적으로 2자리가 할당됩니다.
CREATE TABLE sam02 ( year01 INTERVAL YEAR(3) TO MONTH );
일단 잘 만들어졌는지 구조를 확인합니다. desc sam02;
자료 입력 insert into sam02 values (INTERVAL '36' MONTH(3));
자료 검색 select year01, sysdate, sysdate+year01 from sam02;
003-00 : 3년을 의미 sysdate : 현재 날짜 sysdate+year01 : 현재 날짜에 3년이 지난 후의 날짜를 계산한 결과
2) INTERVAL DAY TO SECOND
INTERVAL DAY(일수에 대한 자리수) TO SECOND(초에 대한 자리수) 자리수를 지정하지 않으면 기본적으로 2자리를 할당합니다.
테이블 만들기 CREATE TABLE sam03 ( day01 INTERVAL DAY(3) TO SECOND );
자료 입력 insert into sam03 values (INTERVAL '100' DAY(3));
자료 검색 select day01, sysdate, sysdate+day01 from sam03; 오늘 날짜에서 100 일 후를 검색합니다.
3) 실습용 사원 테이블 생성
CREATE TABLE em01
( empno NUMBER(4), ename VARCHAR2(20), sal NUMBER(7, 2) );
desc em01;
4) 서브 쿼리를 이용한 테이블 생성 다른 테이블의 구조뿐만 아니라 데이터까지 복사할때 사용.
CREATE TABLE emp02 AS select * from emp;
desc emp; desc emp02; select * from emp02;
CREATE TABLE em03 AS select empno, ename from emp; 원하는 컬럼만 선택적으로 복사.
5) 데이터의 구조만 복사하기 create table em04 as select * from emp where 1=0; where절에 거짓 조건을 주면 결과는 복사되지 않습니다.
6) 테이블 구조 변경
create table em05 as select * from emp;
desc em05;
[컬럼 추가] alter table em05 add(email VARCHAR2(20));
desc em05; 마지막 부분에 email 컬럼이 추가되었습니다.
[컬럼 변경] alter table em05 modify(email VARCHAR2(40)); 변경시 데이터의 크기와 타입을 고려해야 합니다.
desc em05;
[컬럼 삭제] alter table em05 drop column email; 삭제시 데이터까지 지워지므로 복원이 불가능합니다.
desc em05;
다시 email 컬럼을 VARCHAR2(40) 데이터형으로 삽입합니다.
alter table em05 add(email VARCHAR2(40));
삭제를 하지 않고 컬럼의 사용을 논리적으로 제한하는 방법 alter table em05 set unused(email);
desc em05; 컬럼 리스트에서 보이지 않습니다.
그후 가장 사용빈도가 적은 시간에 실제적인 삭제 작업을 진행합니다. alter table em05 drop unused columns;
desc em05;
[테이블 제거] DROP TABLE em04; 자료가 모두 삭제 되므로 주의 해야 합니다. 나중에 찾을지 모르는 자료는 백업을 생활화 해야 합니다.
create table em04_bakup select * from em04; 한후에 drop table em04;
이렇게 해야 좋습니다. ㅋ
[테이블의 모든 로우(데이터) 제거] select * from em05;
truncate table em05;
[데이터 딕셔너리와 데이터 딕셔너리 뷰] Data Dictionary는 데이터베이스 자원을 효율적으로 관리하기 위한 다양한 정보를 저장하는 시스템 테이블 입니다. Data Dictionary는 사용자가 테이블을 생성하거나 사용자를 변경하는 등의 작업을 할 때 데이터베이스 서버에 의해 자동으로 갱신되는 테이블로 사용자는 Data Dictionary의 내용을 직접 수정하거나 삭제할 수 없습니다. Data Dictionary의 내용은 암호화 되어 있습니다. 그렇기 때문에 Data Dictionary View가 필요하게 됩니다.
Data Dictionary View의 접두어 DBA_XXXX 데이터베이스 관리자만 접근 가능한 객체 등의 정보 조회 ALL_XXXX 자신 계정 소유 또는 권한을 부여 받은 객체 등에 과한 정보 조회 USER_XXXX 자신의 계정이 소유한 객체 등에 관한 정보 조회
i) User 데이터 딕셔너리
show user; 현재 사용자 계정 출력
결과: USER is "SCOTT"
desc user_tables; 자신이 소유한 모든 테이블 정보를 조회합니다.
select table_name from user_tables order by table_name desc;
user_sequences 계정이 소유한 시퀀스의 정보 조회 할 수 있는 데이터 딕셔너리 뷰 user_indexes 계정이 소유한 인덱스 정보 조회 할 수 있는 데이터 딕셔너리 뷰 user_views 계정이 소유한 뷰 정보 조회 할 수 있는 데이터 딕셔너리 뷰
ii) ALL_ 데이터 딕셔너리 다른 소유자의 객체에 접근 권한이 있는 사람이 그 객체에 접근할 경우 사용하는 뷰
desc all_tables;
select owner, table_name from all_tables;
user_sequences 현재 계정이 접근 가능한 시퀀스의 정보 조회 user_indexes 현재 계정이 접근 가능한 인덱스 정보 조회 user_views 현재 계정이 접근 가능한 뷰 정보 조회
iii) DBA) 데이터 딕셔너리 뷰 DBA만 접근 가능한 객체등을 조회할 수 있는 뷰.
conn system/manager
select owner, table_name from dba_tables where owner='SYSTEM';
conn scott/tiger
dba_sequences 데이터베이스에 있는 모든 시퀀스의 정보 조회 dba_indexes 데이터베이스에 있는 모든 인덱스 정보 조회 dba_views 데이터베이스에 있는 모든 뷰 정보 조회
1. INSERT 문
INSERT INTO 테이블명 [컬럼명] VALUES [값]
create table dept01 as select * from dept;
desc dept01;
insert into dept01 (deptno, dname, loc) values (60, 'tester', 'Seoul');
select * from dept01;
컬럼명에 해당되는 자료가 입력된다면 컬럼명을 생략해도 됩니다. insert into dept01 values (61, 'tester2', 'Seoul');
insert into dept01 values(62, 'tester3', NULL);
insert into dept01 values(63, 'tester4', '');
2. 치환 변수
select * from &talbe_name; 테이블명을 입력 받습니다.
select &column_name from &table_name; 컬럼명과 테이블명을 입력 받습니다.
select * from emp where &stmt; 조건을 입력 받습니다.
select * from emp where sal > &salary_value; 값을 입력 받습니다.
- && 연산자 입력받은 치환 변수 값이 메모리에 기억되어 계속 사용가능한 연산자
select * from emp_where sal > &&salary_value;
처음 입력값을 입력하고 실행한후 위의 쿼리문을 실행하면 입력없이 실행됩니다.
3. 서브 쿼리로 로우 추가 create table dept02 as select * from dept where 1=0; 1=0 은 거짓으므로 출력 결과 없이 구조만 복사해 옵니다.
insert into dept02 select * from dept;
4. 다중 테이블에 다중 로우 입력하기
desc emp;
create table emp_hir as select empno, ename, hiredate from emp where 1=0;
create table emp_mgr as select empno, ename, mgr from emp where 1=0;
insert all into emp_hir values(empno, ename, hiredate) into emp_mgr values(empno, ename, mgr) select empno, ename, hiredate, mgr from emp where deptno > 20;
select * from emp_hir; select * from emp_mgr;
5. 조건(WHEN)에 의해 다중 테이블에 다중 로우 입력하기
create table emp_hir02 as select empno, ename, hiredate from emp where 1=0;
create table emp_sal as select empno, ename, sal from emp where 1=0;
insert all WHEN hiredate > '01-JUN-1982' THEN into emp_hir02 values (empno, ename, hiredate) WHEN sal > 2000 THEN into emp_sal value (empno, ename, sal) SELECT empno, ename, hiredate, sal FROM emp;
각 요일을 구분할 수 있는 컬럼을 추가하여 매일 매일의 판매 실적을 기록합니다. insert all into sales_data values(sales_id, week_id, 1, mon_sales) into sales_data values(sales_id, week_id, 2, tue_sales) into sales_data values(sales_id, week_id, 3, wed_sales) into sales_data values(sales_id, week_id, 4, thu_sales) into sales_data values(sales_id, week_id, 5, fri_sales) select sales_id, week_id, mon_sales, thu_sales, wed_sales, thu_sales, fri_sales from sales;
select * from sales_data;
7. UPDATE 문
UPDATE 테이블명 SET 컬럼명=변경할값 WHERE 조건
create table dept02 as select * from dept;
desc dept02;
select * from dept02;
dept02 가 이미 생성되었다면 삭제하고 다시 만듭니다. drop table dept02;
update dept02 set loc='Seoul' where deptno=10;
select * from dept02;
create table em06 as select empno, ename, sal from emp; select * from em06;
update em06 set sal=sal*1.1; 모든 직원의 급여를 10% 인상합니다.
select * from em06;
8. 서브 쿼리를 이용한 데이터 수정
create table dept03 as select * from dept;
select * from dept03;
update dept03 set (dname, loc) = (select dname, loc from dept where deptno=40) where deptno=20;
부서번호 20의 부서명과 위치가 dept 테이블의 부서번호 40의 결과로 수정되었습니다.
select * from dept03;
9. delete 문
DELETE FROM 테이블명 WHERE 조건;
select * from dept 03;
delete from dept03 where deptno=30;
create table em07 as select * from emp;
select * from em07;
delete from em07 where deptno=(select deptno from dept where dname='SALES');
select * from em07;
10. MERGE 두개의 테이블을 하나의 테이블로 합치는 기능을 합니다. 기존에 존재하는 행이 있다면 새로운 값으로 갱신되고, 존재하지 않으면 새로운 행으로 추가 됩니다.
create table em08 as select * from emp;
create table em09 as select * from emp where job='MANAGER';
merge into em08 e using em09 s on (e.empno=s.empno) when matched then update set e.ename = s.ename, e.job = s.job, e.mgr = s.mgr, e.hiredate = s.hiredate, e.sal = s.sal, e.comm = s.comm, e.deptno = s.deptno when not matched then insert values ( s.empno, s.ename, s.job, s.mgr, s.hiredate, s.sal, s.comm, s.deptno );
트랜잭션(Transaction)은 데이터의 일관성을 유지하기 위한 일련의 프로세스라고 보시면 됩니다. 트랜잭션은 어느 한단계를 말하는 것이 아니고, COMMIT (성공적으로 반영되거나) ROLLBACK ( 성공적으로 취소되거나) 일련의 단계라고 보시면 됩니다. 즉, 모두 반영되거나 모두 취소되어야 하는 프로세스라고 보시면 됩니다.
두개의 테이블에 입력을 해야 한다고 본다면,
회원정보는 두 개 이상의 테이블을 이용하여 정보를 관리한다고 예를 들죠...
member 테이블과 member_detail테이블이 있다면, 회원 가입시 member 테이블에 반드시 입력되어야 하는 값이 누락되었거나 잘못된 값일 경우, member_detail 입력에 도달하기도 전에 모든 작업이 취소되어야 한다는 의미이고, member 테이블에 입력되어야 할 값이 정상이지만 member_detail 테이블에 입력될 값이 또한 중요한 값이 누락되었거나 잘못된 값일 경우 입력이 되지 말아야 합니다. 이럴 때, 정보가 누락이 되었으니 다시 입력해 달라는 문구가 사용자에게 피드백되어야 하죠... 어느 하나 입력이 누락이되면 모두 취소되어야 하는 경우는?ROLLBACK모두 정상적으로 입력이 반영되었다면?COMMIT
COMMIT 되고 ROLLBACK 되고 하는 일련의 과정을 트랜잭션이라고 보시면 쉽습니다.
commit; 먼저 이전에 했던 작업을 모두 적용시키기 위해서 커밋을 수행합니다.
delete from dept01;
select * from dept01;
rollback;
select * from dept01; 롤백으로 인하여 자료가 다시 이전 상태로 복원되었음을 확인 합니다.
delete from dept01 where deptno=20;
select * from dept01 where deptno=20;
commit;
rollback;
select * from dept01 where deptno=20; 복원되지 않습니다. 이미 commit 이 수행된 결과는 롤백되지 않습니다.
[자동 커밋] DDL문에는 CREATE, ALTER, DROP, RRENAME, TRUNCATE 등의 자동 커밋(AUTO COMMIT)이 발생하는 DDL문이 있습니다. 이런 경우에는 ROLLBACK 가 불가능합니다.
create table em10 as select * from emp;
delete from em10 where deptno=10;
select * from em10 where deptno=10; 결색결과 없음 확인
truncate table emppp; 없는 테이블 명으로 오류를 유발
rollback;
select * from em10 where deptno=10 결과가 없습니다. truncate 가 수행되면 현재 수행된 모든 작업이 커밋이 되므로 롤백이 불가능 합니다.
[세이브 포인트]
SAVEPOINT C3; ... ... ROLLBACK TO C3;
롤백이 수행되면 savepoint c3 으로 복원 됩니다.
COMMIT
CREATE TABLE dept05 as select * from dept;
select * from dept05;
savepoint A;
delete from dept05 where deptno=20;
select * from dept05 where deptno=20;
rollback to A;
select * from dept05 where deptno=20; 복원 되었습니다.
주의)
savepoint A;
명령 수행...
savepoint B; 명령수행...
rollback to A;
이렇게 A 포인트로 롤백될 경우, B포인트로의 롤백은 불가능합니다. A 포인트로 롤백되었다는 의미는 B포인트의 위치도 함께 사라짐을 의미 합니다.
data integrity constraint rule이란 테이블에 부적절한 자료가 입력되는 것을 방지하기 위해서 테이블을 생성할 때 각 컬럼에 대해서 정의하는 여러가지 규칙을 말합니다.
alter table dept03 add constraint dept03_deptno_pk PRIMARY KEY(deptno);
3. 제약 조건 제거 alter table dept03 drop constraint dept03_dname_pk;
4. 참조 제약 조건 // 기본 키 지정 create table dept07 ( deptno NUMBER(2), dname VARCHAR2(15), loc VARCHAR2(15), constraint dept07_deptno_pk PRIMARY KEY(deptno) );
ename VARCHAR2(15), sal NUMBER(7, 2) constraint emp08_sal_ch CHECK(sal between 500 and 5000), deptno NUMBER(2) constraint emp08_deptno_fk references dept08 (deptno) );
7. NOT NULL 제한 조건 create table dept09 ( deptno NUMBER(4) constraint dept09_deptno_pk PRIMARY KEY, dname VARCHAR2(15) constraint dept09_dname_nn NOT NULL, loc VARCHAR2(15) );
// 수정 alter table dept09 modify loc constraint dept09_loc_nn NOT NULL;
// 제거 alter table dept09 drop loc constraint dept09_loc_nn;
// 제약 조건을 참조하는 모든 제약 조건들도 먼저 제거한후 현재 제약 조건을 삭제 시킴 alter table dept09 drop constraint dept09_deptno_pk CASCADE;
// 제약 조건을 비활성화 alter table dept09 disable constraint dept09_deptno_pk;
// 비활성화 된 제약 조건 활성화 alter table dept09 enable constraint dept09_deptno_pk;
뷰란? 물리적인 테이블을 근거한 논리적인 가상 테이블이라고 정의할 수 있습니다.
create table dept_copy as select * from dept;
create table emp_copy as select * from emp;
30번 부서에 소속된 사원들의 사번과 이름, 부서번호가 자주 검색된다고 했을때, 뷰가 필요한 이유 설명.
select empno, ename, deptno from emp_copy where deptno=30;
위에서 처럼 매번 같은 실행문을 작성해야 한다면 번거로울겁니다.
이럴때 필요한 것이 없을까 생각해서 작성되어야하는 것이 뷰 입니다.
create view emp_view30 as select empno, ename, deptno from emp_copy where deptno=30;
desc emp_view30;
뷰의 구조는 기본테이블의 구조를 그대로 상속받습니다.
실행은 select * from emp_view30;
정말 간단하죠?
[뷰를 사용하는 이유] 1) 복잡하고 긴 쿼리문을 뷰로 정의하면 접근을 단순화시킬 수 있습니다. 2) 보안에 유리 합니다.
보안에 유리한 이유는 뷰에 작성된 쿼리 정보에는 급여등 중요한 정보가 제한되어 있기 때문에 중요한 정보를 보호할 수 있습니다.
[뷰의 종류]
1. 단순 뷰와 컨럼 별칭
create view emp_view10(사원번호, 이름, 부서번호) as select empno, ename, deptno from emp_copy where deptno=10;
select * from emp_view10;
결과 컬럼명이 한글로 보여집니다. 이것이 컬럼명을 별칭으로 사용한 예입니다.
desc emp_view10;
create view dept_sum as select deptno, SUM(sal) sum_sal from emp_copy group by deptno;
사원테이블에서 부서별 급여 총계를 구하는 뷰 입니다.
select * from dept_sum;
2. 복합 뷰
create view emp_view_join as select e.empno, e.ename, d.dname
from emp e, dept d where e.deptno=d.deptno;
select * from emp_view_join;
복잡한 쿼리문을 뷰를 통해서 간단하게 접근할 수 있는 것을 확인할 수 있습니다.
3. 뷰의 제거 drop view emp_view30; drop view emp_view10; drop view emp_view;
4. 뷰의 변경 drop view detp_sum;
create view dept_sum as select deptno, sum(sal) sum_sal, avg(sal) avg_sal from emp_copy group by deptno;
select * from detp_sum;
뷰의 변경은 create or replace view 를 이용합니다.
create or replace view emp_view_join as select e.name, d.name, d.loc from emp e, dept d where e.deptno=d.deptno;
select * from emp_view_join;
5. 뷰의 생성할 때 지정하는 FORCE/NOFORCE 옵션 기본 테이블이 존재하지 않을 경우에도 뷰를 생성할 수 있는데 이 때 사용하는 옵션이 FORCE 입니다.
특별한 설정이 없으면 NOFORCE 옵션이 지정된 것이므로 반드시 존재하는 기본 테이블을 이용한 쿼리문으로 뷰를 생성해야 합니다.
desc employees; 물론 존재하지 않는 기본 테이블이니 오류 메시지를 보여줍니다.
create or replace view view_employees as select * from employees;
테이블 또는 뷰가 존재하지 않습니다 라는 오류를 보여 줍니다.
이럴때 사용하는 옵션이 FORCE 옵션입니다.
create or replace force view view_employees as select * from employees;
컴파일 오류와 함께 뷰가 생성되었습니다.
6. WITH CHECK OPTION
create or replace noforce view emp_view20 as select empno, ename, deptno from emp_copy where deptno=20;
select * from emp_view20;
update emp_view20 set ename='nekr' where empno=7369;
select * from emp_view20;
update emp_view20 set deptno=40 where empno=7369;
부서번호 20인 사원만 검색되는 뷰인데 40으로 변경되었으니 뷰 검색에는 나오지 않게 됩니다.
create or replace noforce view emp_view20 as select empno, ename, deptno from emp_copy where deptno=20 with check option;
지급부터는 deptno 는 변경이 불가능하게 됩니다.
7. WITH READ ONLY
create or replace noforce view emp_chk30 as select empno, ename, deptno from emp_copy where deptno=30 with read only;
with read only 옵션을 지정하게 되면, 기본 테이블의 내용을 변경할수 없게 도비니다.
8. 인라인 뷰
서브 쿼리문에서 바깥 쪽 select 문이 from 절 내부에 사용된 서브 쿼리문을 말합니다. 내부에 사용되는 서브 쿼리는 별칭이 부여 됩니다.
select src.empno, src.ename, src.hiredate, src.deptno, max_hiredte from emp_copy src, (select deptno, MAX(hiredate) max_hiredate from emp_copy group by deptno) des where src.deptno=des.deptno and src.hiredate < des.max_hiredate;
9. Top-N 분석
select rowid, rownum, empno from emp;
rowid : 주소로서 row 가 실제로 저장되어 있는 공간(Tree형 구조) 테이블 내의 고유주소 rownum : 번호인데 row의 주소 순서대로 출력되어지는 순서대로 부여됩니다.
이 두개 컬럼을 이용하여 Top-N 쿼리문을 작성할수 있습니다.
select ename, sal from emp order by sal desc;
select rownum, ename, sal from (select ename, sal, from emp order by sal desc); 급여를 기준 컬럼으로 내림차순 정렬한 사원 테이블을 인라인 뷰로 구성. 급여를 가장 많이 받는 사원이 첫 행이 됩니다.
select rownum, ename, sal from (select ename, sal, from emp order by sal desc) where rownum <= 3;
rownum 값이 3까지만 조회 됩니다.
select rownum, empno, ename, hiredate from ( select empno, ename, hiredate from emp order by hiredate desc ) where rownum <= 5; 최근에 입사한 직원 5명에 대한 정보를 출력하는 쿼리문 입니다.
1. 시퀀스란 오라클에서는 행을 구분하기 위해서 기본 키를 두고 있습니다. 기본키는 중복된 값을 가질 수 있으므로 항상 유일한 값을 가져야 합니다. 기본키가 유일한 값을 갖도록 사용자가 직접 값을 생성해내려면 부담이 큽니다.시퀀스는 테이블 내의 유일한 숫자를 자동으로 생성하는 자동번호발생기이므로 시퀀스를 기본 키로 사용하게 되면 사용자의 부담을 줄일 수 있습니다. CREATE SEQUENCE sequence_name [ INCREMENT BY n ] [ START WITH ] [ {MAXVALUE n | NOMAXVALUE} ] [ {MINVALUE n | NOMINVALUE} ] [ {CYCLE| NOCYCLE} ] [ {CACHE n | NOCACHE} ];
1) INCREMENT BY 옵션 연속적인 시퀀스 번호의 증가치를 지정할 때 사용됩니다. 만약 1씩 증가하는 시퀀스를 생성하려면 increment by 1 이라고 지정해주면 됩니다.
2) START WITH 옵션 시퀀스 번호의 시작 값을 지정할 때 사용됩니다. 만일 1부터 시작되는 시퀀스를 생성하려면 start with 1 로 지정해주면 됩니다.
3) MAXVALUE 옵션 시퀀스가 가질 수 있는 최대값을 지정합니다. nomaxvalue 를 지정하면 ascending 순서일 경우에는 10^27 승이고, descending 순서일 경우에는 -1 로 설정됩니다.
4) MINVALUE 옵션
시퀀스가 가질 수 있는 최소값을 지정합니다. nominvalue 를 지정하면 ascending 순서일 경우에는 1이고 descending 순서일 경우에는 10^26 승이 설정됩니다.
5) CYCLE 옵션 지정된 시퀀스 값이 최대값까지 증가가 완료되게 되면 다시 start with 옵션에 지정한 시작 값에서 다시 시퀀스를 시작하도록 합니다. nocycle 은 증가가 완료되게 되면 에러를 유발시킵니다.
6) CACHE 옵션 메모리상의 시퀀스 값을 관리하도록 하는 것인데 기본 값은 20입니다. nocache는 원칙적으로 메모리 상에서 시퀀스를 관리하지 않습니다.
부서번호를 자동으로 부여해주는 시퀀스 객체를 생성 create sequence detp_deptno_seq increment by 10 start with 10;
2. CURRVAL 과 NEXTVAL 의 사용 시퀀스의 현재 값을 알아내기 위해 currval 을 사용하고, 다음 값을 알아내기 위해 nextval을 사용합니다.
currval에 새로운 값을 할당하기 위해서는 nextval로 새로운 값을 생성해야 합니다.
select dept_deptno_seq.nextval from dual;
select dept_deptno_seq.currval from dual;
create sequence sample_seq;
select sample_seq.nextval from dual; select sample_seq.currval from dual;
3. 시퀀스의 수정과 제거
alter sequence dept_deptno_seq maxvalue 50;
select dept_deptno_seq.currval from dual; select dept_deptno_seq.nextval from dual; select dept_deptno_seq.currval from dual;
nextval를 할당하다 보면 50까지만 할당하고 그 이상은 오류를 발생합니다.
시퀀스의 제거 drop sequence sample_seq; drop sequence dept_deptno_seq;
4. 시퀀스의 실무 적용 99.9% insert 연산과 같이 사용되어 컬럼 값을 자동으로 발생시키는 용도로 사용됩니다.
create table dept15
( detpno NUMBER(4) PRIMARY KEY, dname VARCHAR2(25), loc VARCHAR2(30) );
desc dept15;
create sequence dept_deptno_seq increment by 10 start with 10 nocycle;
insert into dept15 values (dept_deptno_seq.nextval, 'test1', 'location1'); insert into dept15 values (dept_deptno_seq.nextval, 'test2', 'location2'); insert into dept15 values (dept_deptno_seq.nextval, 'test3', 'location3'); insert into dept15 values (dept_deptno_seq.nextval, 'test4', 'location4');
select * from dept15;
1. 인덱스란? 검색을 빠른 속도로 하기 위해서 제공됩니다. SQL 명령문의 처리 속도를 향상시키기 위해서 컬럼에 대해서 생성하는 오라클 객체입니다. 오라클에서의 인덱스의 내부 구조는 B트리 형식으로 구성되어 있습니다.
2. 인덱스 생성/제거, 조회
create table e2 as select * from emp;
검색속도의 차이를 현저히 느끼게하려면 데이터가 많아야 합니다. 데어터 부풀리기... inert into e2 select * from e2; 여러번 실행해서 행을 많이 생성해 놓습니다. 저는 하다보니 917504 rows created 가 되었네요
시간 체크를 위해 set timing on
select distinct empno, ename from e2 where ename='SCOTT'; 01.95 초 약 2초 걸렸네요...
create index idx_e2_ename on e2(ename); 인덱스 생성하는 시간이 좀 걸리는군요. 28.56 초 걸렸습니다.
select distinct empno, ename from e2 where ename='SCOTT'; 다시 검색해 봅니다. ㅋ 개인별 노트북 사양이 틀려서 이겠지만 많은 양의 데이터 검색에서는 차이가 날겁니다.
인텍스 삭제 drop index idx_e2_ename;
3. 인덱스의 장/단점, 인덱스 재구성
1) 인덱스를 사용해야하는 경우 테이블에 행의 수가 많을 때 조건절인 where 문에 해당 컬럼이 많이 사용될 때 검색 결과가 데이터의 2% ~ 4% 정도 일 때 join에 자주 사용되는 컬럼 NULL을 포함하는 컬럼이 많은 경우
2) 인덱스를 사용하지 말아야 하는 경우 테이블에 행의 수가 적을 때 where 문에 해당 컬럼이 자주 사용되지 않을 때 검색 결과가 전체 데이터의 10% ~ 15% 이상 높을 때 테이블에 DML 작업이 많은 경우( 입력 수정 삭제 등이 자주 발생할 때)
select * from e2 where deptno=10;
테이블에 전체 행의 수는 10000 건이다. 위의 쿼리문을 전체 쿼리문 들 중 95% 사용된다. 쿼리문의 결과에 구해지는 행은 10건 정도이다. 그래서 인덱스가 필요합니다.
create index idx_e2_deptno on e2(deptno); 생성완료시간: 7.98초
효율이 떨어지면 인덱스를 재생성해 주어야 합니다. 컬럼의 데이터가 입력, 수정, 삭제될 경우 해당 컬럼에 의해 생성된 인덱스에 대해서 재구성해야 합니다.
인덱스의 재생성
alter index idx_e2_deptno rebuild;
4. 인덱스의 종류 1) 고유 인덱스(Unique Index) - 유일한 값을 갖는 컬럼에 대해서 생성하는 인덱스2) 비고유 인덱스(NonUnique Index) - 중복된 데이터를 갖는 컬럼에 대해서 생성하는 인덱스3) 단일 인덱스(Single Index) 4) 결합 인덱스(Composite Index) 5) 함수 기반 인덱스(Function Based Index)
create table d2 as select * from dept;
insert into d2 values (50, 'test50', 'Seoul'); insert into d2 values (60, 'test60', 'Daejeon'); insert into d2 values (70, 'test70', 'Daejeon');
select * from d2;
deptno 에 대해서는 고유인덱스를
loc 에 대해서는 비고유인덱스를 생성하는것이 좋습니다.
[고유인덱스] crete unique index idx_d2_deptno on d2(deptno);
[비고유인덱스] create index idx_d2_loc on d2(loc);
[결합 인덱스] create index idx_d2_com on d2(deptno, loc);
select index_name, column_name from user_ind_columns where table_name='d2'; 인덱스 구조 확인 합니다.
[함수기반 인덱스]
create table e3 as select * from emp;
검색 조건으로 sal*12 = 3600 을 지정하는 경우, 이럴경우 sal*12 를 인덱스를 탈수 없을수도 있습니다. 이럴때 구성하는 인덱스가 함수 기반 인덱스 입니다.
create index idx_e3_annsal on e3(sal*12);
select index_name, column_name from user_ind_columns where table_name='e3'; 인덱스 생성 확인...
1. 사용자 생성
conn system/manager
show user
system 사용자로 접속했는지 확인
create user user01 identified by tiger; User id : user01 User pw : tiger 로 유저 생성
2. 시스템 권한 1) 데이터베이스 관리자가 가지는 시스템 권한 CREATE USER 새롭게 사용자를 생성하는 권한 DROP USER 사용자를 삭제하는 권한 DROP ANY TABLE 임의의 테이블을 삭제할 수 있는 권한 QUERY REWRITE 질의 재작성을 할 수 있는 권한 BACKUP ANY TABLE 임의의 테이블을 백업할 수 있는 권한
2) 일반 사용자에 데이터베이스를 관리하는 권한 CREATE SESSION 데이터베이스에 접속할 수 있는 권한 CREATE TABLE 사용자 스키마에서 테이블을 생성할 수 있는 권한 CREATE VIEW 사용자 스키마에서 뷰를 생성할 수 있는 권한 CREATE SEQUENCE 사용자 스키마에서 시퀀스를 생성할 수 있는 권한 CREATE PROCEDURE 사용자 스키마에서 함수를 생성할 수 있는 권한
3) 사용자에게 시스템 권한 부여하기 위한 GRANT 명령어
grant system_privilege to user_name
grant create session to user01;
conn user01/tiger show user
성공적으로 접속 되었습니다. ㅋ
4) WITH ADMIN OPTION 옵션 사용자에게 시스템 권한을 WITH ADMIN OPTION과 함께 부여하면 그 사용자는 데이터베이스 관리자가 아닌데도 불구하고 부여받은 시스템 권한을 다른 사용자에게 부여할 수 있는 권한도 함께 부여받게 됩니다.
conn system/manager
create user user02 identified by tiger; create user user03 identified by tiger;
grant create session to user02 with admin option; grant create session to user03;
conn user02/tiger grant create session to user01; user02 가 시스템 권한행사가 가능함을 볼수 있다.
conn system/manager
5) 객체 권한 테이블이나 뷰, 시퀀스, 함수등과 같은 객체별로 DML문(select, insert, delete)을 사용할 수 있는 권한을 설정.
GRANT object_privilege ON object TO user_name
conn user01/tiger show user select * from emp;
검색할수 없습니다.
객체 권한이 없기 때문이죠...
emp는 scott 사용자 소유의 테이블 입니다.
conn scott/tiger
grant select on emp to user01;
conn user01/tiger
select * from emp; 그래도 검색이 불가능합니다.
select * from scott.emp; 이렇게 해주면 검색가능합니다.
6) 사용자에게 부여된 권한 조회 conn user01/tiger
select * from user_tab_privs_made; //user01 사용자가 부여한 권한을 살펴봄 select * from user_tab_privs_recd; //user01 사용자에게 부여된 권한을 살펴봄
conn scott/tiger
select * from user_tab_privs_made; //scott 사용자가 부여한 권한을 살펴봄 select * from user_tab_privs_recd; //scott 사용자에게 부여된 권한을 살펴봄
7) 사용자에게 권한을 빼앗기 위한 REVOKE 명령어
REVOKE object_privilege on object from user_name
conn scott/tiger
revoke select on emp from user01; select * from user_tab_privs_made;
conn user01/tiger select * from scott.emp;
검색 불가능...
1. 사전 정의된 롤의 종류
1) CONNECT 롤 사용자가 데이터베이스에 접속 가능하도록 하기 위해 다음과 같이 가장 기본적인 시스템 권한 8가지를 묶어 놓았습니다.
3) DBA 롤 사용자들이 소유한 데이터베이스를 관리하고 사용자들을 작성하고 변경하고 제거할 수 있도록 하는 모든 권한을 가집니다.
2. 롤 부여하기
conn system/manager
create user user04 identified by tiger
grant connect, resource to user04;
conn user04/tiger
select * from user_role_privs;
3. 사용자가 롤 정의
conn system/manager
create role mrole;
conn scott/tiger
grant select on emp to mrole;
conn system/manager
grant mrole to user04;
conn user04/tiger
select * from scott.emp;
검색 가능하게 되었습니다.
4. 롤에 부여된 권한 알아보고 롤 회수하기
conn test04/tiger
select * from role_tab_privs where table_name in ('EMP');
select * from user_role_privs;
conn system/manager
revoke mrole from user04; 권한롤을 회수 합니다.
select * from role_tab_privs where role in ('MROLE'); 회수는 했지만 mrole 은 존재함을 확인할수 있습니다.
mrole 제거 drop role mrole; select * from role_tab_privs where role in ('MROLE'); mrole이 존재하지 않습니다.
5. 롤의 장점 권한을 사용자마다 일일이 부여할 필요가 없어집니다.
conn system/manager
create role def_role; grant create session to def_role; grant create table to def_role;
conn scott/tiger grant update on emp to def_role; grant delete on emp to def_role; grant select on emp to def_role;
수정,삭제,검색 권한을 def_role 에 부여함.
conn system/manager
create user userA1 identified by tiger; create user userA2 identified by tiger; create user userA3 identified by tiger;
grant def_role to userA1; grant def_role to userA2; grant def_role to userA3;
select * from role_sys_privs where role='DEF_ROLE'; 시스템 권한에 대한 정보를 저장한 데이터 딕셔너리 검사 select * from role_tab_privs where role='DEF_ROLE'; 객체 권한에 대한 정보를 저장한 데이터 딕셔너리 검사
각 사용자로 접속해서 사용자에게 def_role 롤이 설정되어 있는지 확인 conn userA1/tiger
select * from user_role_privs;
conn userA2/tiger select * from user_role_privs;
conn userA3/tiger select * from user_role_privs;
1. 동의어 개념과 종류 다른 데이터베이스 객체에 대한 별명을 말합니다.
여러 사용자들이 테이블을 서로 공유하는데, 다른 사용자의 테이블을 접근할 때 [사용자명.테이블명]으로 표현하는 데, 이를 동의어를 적용하면 간단하게 요약해서 기술할 수 있습니다.
CREATE [PUBLIC] SYNONYM synonym_name FOR user_name.object_name;
synonym_name : user_name.Object_name에 대한 별칭입니다. user_name : 객체를 소유한 오라클 사용자입니다. object_name : 동의어를 만들려는 데이터베이스 객체 이름입니다.
DUAL 테이블은 공개 동의어입니다.
2. 동의어 생성
conn system/manager
create role test_role; grant connect, resource to test_role;
conn scott/tiger grant select on emp to test_role; grant select on dept to test_role;
conn system/manager
create user userb1 identified by tiger; create user userb2 identified by tiger;
grant test_role to userb1; grnat test_role to userb2;
create public synonym pub_dept for scott.dept;
conn userb1/tiger select * from pub_dept; 드디어 검색이 가능합니다.
동의어 삭제하기 conn system/manager drop public synonym pub_dept;
1. PL/SQL 구조
PL/SQL 은 파스칼 구조로 DECLARE ~ BEGIN ~ EXCEPTION ~ END 순서를 갖습니다.
DECLARE SECTION(선언부) PL/SQL에서 사용하는 모든 변수난 상수를 선언하는 부분으로 DECLARE로 시작합니다.
EXECUTABLE SECTION(실행부) 절차적 형식으로 SQL문을 실행할 수 있도록 절차적 언어의 요소인 제어문, 반복문, 함수정의 등 로직을 기술할 수 있는 부분으로 BEGIN 으로 시작합니다.
EXCEPTION SECTION(예외 처리부) PL/SQL 문이 실행된는 중에 에러가 발생할 수 있는데 이를 예외 사항이라고 합니다. 이러한 예외 사항이 발생했을 때 이를 해결하기 위한 문장으로 구성됩니다.
ed sample 를 실행하여 메모장에서 편하게 아래 쿼리문을 작성합니다.
declare vempno NUMBER(4); vename VARCHAR(20); begin select empno, ename into vempno, vename from emp where empno=7788; end; /
작성이 완료되면 창을 닫기위해 X 를 클릭합니다. 저장합니다.
작성한것을 실행합니다. @sample
실행결과 PL/SQL procedure successfully completed. 라는 메시지가 출력 됩니다.
desc dbms_output
출력값이 보이지 않기때문에 sample 을 수정합니다. ed sample
declare vempno NUMBER(4); vename VARCHAR(20); begin select empno, ename into vempno, vename from emp where empno=7788;
1) 스칼라(scalar) 변수 선언 DECLARE vempno NUMBER(4); vename VARCHAR2(20);
2) %TYPE 변수 선언 vdeptno emp.deptno%TYPE; 컬럼의 데이터타입 및 사이즈를 참조 합니다.
3) %ROWTYPE vemp emp%ROWTYPE; emp 테이블의 ROW 타입(empno, ename, job, mgr, hiredate, sal, comm, deptno)과 같다는 의미입니다. emp 테이블 안에 들어 있는 8개의 컬럼 및 사이즈를 참조한 8개의 칸으로 나눠진 한 줄의 변수라고 생각 할 수 있습니다.
ed example03
declare vemp emp%ROWTYPE; begin select * into vemp from emp where empno=7788;
한가지 주의 할점은 우리가 알고 있는 이반적인 else if 또는 elseif 와는 같은 의미이지만 ELSIF 를 보시면 영문자 e가 없습니다. 참 별것이 말썽이군요.. 파스칼 문법은 ELSEIF 인데 이상하군요 ㅋ
3) IF~THEN~ELSE~END IF
ed ex03
declare vempno NUMBER(4); vename VARCHAR2(20); vcomm emp.comm%TYPE; begin select empno, ename, comm into vempno, vename, vcomm from emp where empno=7788;
if (vcomm > 0) then dbms_output.put_line(vename||' comm : '||vcom); else dbms_output.put_line(vename||' comm : 0'); end if; end; /
저장하고 실행 @ex03 SCOT comm : 0
PL/SQL procedure successfully completed.
4) 반복문 ed ex04
SET SERVEROUTPUT ON declare VDAN NUMBER(2) := 2; I NUMBER(2) default 0; TOT NUMBER:=0;
begin for I in 1..9 loop TOT := VDAN * I; dbms_output.put_line(VDAN||' * '||I||' = '||TOT); end loop; end; /
저장하고 실행 @ex04 곱하기 2단 실행결과 출력됩니다.
PL/SQL procedure successfully completed.
단수를 입력받고 출력하기 ed ex05
SET SERVEROUTPUT ON ACCEPT PDAN PROMPT 'INPUT DAN : ' declare VDAN NUMBER(2) := &PDAN; I NUMBER(2) default 0; TOT NUMBER:=0; begin for I in 1..9 loop TOT := VDAN * I; dbms_output.put_line(VDAN||' * '||I||' = '||TOT); end loop; end; /
저장하고 실행하기
@ex05 3을 입력하고 엔터 클릭하시면 3단의 결과가 나옵니다.
PL/SQL procedure successfully completed.
5) 테이블에 저장
set serveroutput off
create table a ( A1 NUMBER, A2 NUMBER, A3 NUMBER );
desc a;
ed ex06
SET SERVEROUTPUT ON ACCEPT PDAN PROMPT 'INPUT DAN : ' declare VDAN NUMBER(2) := &PDAN; I NUMBER(2) default 0; TOT NUMBER:=0; begin for I in 1..9 loop TOT := VDAN * I; dbms_output.put_line(VDAN||' * '||I||' = '||TOT); insert into A values(VDAN, I, TOT); end loop; end; /
저장하고 실행
@ex06 5를 입력하고 엔터 구구단 5단이 출력되고 DB A테이블에 입력됩니다.
PL/SQL procedure successfully completed.
select * from A;
6) 시퀀스 생성
alter table A add(a_no NUMBER);
desc A;
create sequence A_NO_SEQ start with 1 increment by 1 nocycle nocache;
ed ex07
SET SERVEROUTPUT ON ACCEPT PDAN PROMPT 'INPUT DAN : ' declare VDAN NUMBER(2) := &PDAN; I NUMBER(2) default 0;
TOT NUMBER:=0; begin for I in 1..9 loop TOT := VDAN * I; dbms_output.put_line(VDAN||' * '||I||' = '||TOT); insert into A values(VDAN, I, TOT, A_NO_SEQ.nextval); end loop; end; /
저장하고 실행 @ex07 6을 입력하고 엔터
6단이 출력되고 db 입력 됩니다.
7) PL/SQL 테이블과 레코드
TYPE type_name IS TABLE OF table_name.column_name%TYPE INDEX BY BINARY_INTEGER;
type_name 은 새로 정의할 자료 형의 이름입니다. table_name 테이블의 column_name 컬럼의 자료형을 배열로 사용할 새로운 테이블 형인 type_name 의 기본형이 됩니다. 이렇게 선언된 테이블형으로 변수를 선언합니다. INDEX BY 절은 몇 번째 배열에 어떤 값을 저장할 것인지를 구분하기 위해서 사용됩니다.
TYPE E1_TABLE_TYPE IS TABLE OF EMP.ENMAME%TYPE INDEX BY BINARY_INTEGER;
ed ex08
SET SERVEROUTPUT ON declare vename VARCHAR2(20);
TYPE E1_TABLE_TYPE IS TABLE OF emp.ename%TYPE index by binary_integer;
TAB1 E1_TABLE_TYPE; begin select ename into vename from emp where empno=7788;
TAB1(0) := vename;
dbms_output.put_line(TAB1(0)); end;
/
저장하고 실행합니다.
@ex08
SCOTT 라고 나옵니다.
// 부서 테이블을 레코드 배열 형태로 저장하기 위한 새롭게 자료형을 생성
ed ex09
SET SERVEROUTPUT ON declare TYPE D1_RECORD_TYPE IS RECORD ( deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR(13) );
REC1 D1_RECORD_TYPE; begin select * into REC1 from dept where deptno=10;
커서란 SQL Plus에서 사용자가 실행한 SQL문의 단위를 의미합니다. 오라클렝서 수행한 모든 쿼리문은 커서 단위로 처리합니다.
PL/SQL의 SQL문처럼 하나의 결과를 리턴하는 경우 커서 없이도 SQL문의 실행결과가 암시적으로 커서에 저장되므로 이를 암시적 커서라고 합니다.
SQL문을 수행한 후에 결과로 얻어지는 행이 여러 개일 경우에는 암시적인 커서에 정보를
저장할 수 없기에 에러가 발생합니다. 이럴 경우에는 반드시 명시적인 커서를 사용해야 합니다.
명시적인 커서는 PL/SQL의 레코드(RECORD)와 PL/SQL의 테이블(TABLE)을 결합한 것으로서 프로그램 언어의 구조체 배열과 유사합니다.
[커서의 사용]
1) 커서를 선언한다. CURSOR cur_name
2) 커서를 오픈한다. OPEN cur_name
3) 커서에 조회한 결과를 인출해 지정한다. FECTCH cur_name ...
4) 커서를 닫는다 CLOSE cur_name
2. 20번 부서에 근무하는 사원의 정보를 출력하는 예제
ed cur01
SET SERVEROUTPUT ON declare vempno NUMBER(4); vename VARCHAR2(20); vsal NUMBER(7, 2);
CURSOR C1 IS select empno, ename, sal from emp where deptno=20;
begin OPEN C1;
dbms_output.put_line('empno ename sal');
LOOP FETCH C1 INTO vempno, vename, vsal; EXIT WHEN C1%NOTFOUND;
dbms_output.put_line(to_char(vempno)||' '||vename||' '||to_char(vsal)); END LOOP;
end; /
저장하고 실행합니다.
@cur01 empno ename sal 7369 SMITH 800 ... ... ... ... ...
PL/SQL procedure successfully completed.
3. OPEN-FETCH-CLOSE가 없이 커서 처리
ed cur02
SET SERVEROUTPUT ON declare vemp emp%ROWTYPE;
CURSOR C1 IS select empno, ename, sal from emp where deptno=20;
begin dbms_output.put_line('empno ename sal');
FOR vemp IN C1 LOOP EXIT WHEN C1%NOTFOUND;
dbms_output.put_line(to_char(vemp.empno)||' '||vemp.ename||' '||to_char(vemp.sal)); END LOOP;
end; /
정장하고 실행합니다.
@cur02 empno ename sal 7369 SMITH 800 ...
...
...
...
...
PL/SQL procedure successfully completed.
4. 커서의 상태
%NOTFOUND 커서 영역의 자료가 모두 FETCH 됬는가를 알려줌 %FOUND 커서 영역에 FETCH가 되지 않은 자료가 있는가를 알려줌 %ISOPEN 커서가 OPEN된 상태인가를 알려줌 %ROWCOUNT FETCH된 RECORD가 몇 개 있는지 알려줌
cur02 예제를 수정합니다.
ed cur02
SET SERVEROUTPUT ON declare vemp emp%ROWTYPE;
CURSOR C1 IS select empno, ename, sal from emp where deptno=20;
begin dbms_output.put_line('empno ename sal record count');
FOR vemp IN C1 LOOP EXIT WHEN C1%NOTFOUND;
dbms_output.put_line(to_char(vemp.empno)||' '||vemp.ename||' '||to_char(vemp.sal)||' '||C1%ROWCOUNT); END LOOP;
end; /
저장하고 실행합니다.
@cur02
결과는 record count 추가되었습니다.
5. 커서를 활용한 실용 예제 1) 급여 총합을 구하는 예제 ed cur03
SET SERVEROUTPUT ON declare tot NUMBER := 0;
CURSOR emp_cursor IS select ename, sal from emp;
begin dbms_output.put_line('name sal'); dbms_output.put_line('------------------------------------------');
FOR cur_var IN emp_cursor LOOP tot := tot + cur_var.sal; dbms_output.put_line(cur_var.ename); dbms_output.put_line('- '||cur_var.sal); END LOOP; dbms_output.put_line('------------------------------------------'); dbms_output.put_line('- '||tot); end; /
저장하고 실행합니다
@cur03
2) 사원별 급여 현황을 그래포로 표현 ed cur04
SET SERVEROUTPUT ON declare CURSOR emp_cursor IS select ename, sal from emp order by sal desc;
star varchar2(100); cnt number := 0;
begin dbms_output.put_line(' sal of emp'); dbms_output.put_line('------------------------------------------');
FOR cur_var IN emp_cursor LOOP star := NULL; cnt := round(cur_var.sal/100, 0);
for i in 1.. cnt loop star := star||'*'; end loop;
dbms_output.put_line(cur_var.ename); dbms_output.put_line('- '||star||'('||cur_var.sal||')'); END LOOP; end; /
저장하고 실행합니다
@cur04
저장된 PL/SQL을 저장 프로시저라고 합니다.
1. 저장 프로시저 생성 1) 테스트 테이블 생성 crete table emp_cp01 as select * from emp;
2) 저장 프로시저 작성 ed fun01
create or replace procedure del_all is begin delete from emp_cp01; end; /
저장하고 실행합니다. @fun01
프로지저가 생성되었습니다.
실제 실행은
execute del_all 입니다. fun01 은 프로시저를 생성하기 위한 sql문입니다. 프로지저는 fun01.sql에서 정의된 함수명입니다.
실행하게 되면 emp_cp01의 자료를 모두 지웁니다.
확인 select * from emp_cp01;
2. 저장 프로시저 작성시 발생하는 오류 처리
SHOW ERROR 를 수행하여 오류메시지를 확인후 편집기를 띄워서 해당 sql문을 수정합니다. 그리고 다시 @fun01 처럼 프로시저를 생성시켜주고, 최종적으로 테스트를 하기위해 execute del_all 을 수행하면 오류처리가 완료됩니다.
3. 저장 프로시저 조회 저장 프로시저는 데이터 딕셔너리 중에서 user_source라는 뷰에 있습니다.
desc user_source
select name, text from user_source;
4. 매개 변수
1) 테스트 테이블 생성 create table emp_cp02 as select * from emp;
2) PL/SQL 작성 ed fun02
create or replace procedure del_ename(vename emp_cp02.ename%TYPE) is begin delete from emp_cp02 where ename=vename; end; /
저장하고 PL/SQL 을 실행하여 프로시저를 생성합니다. @fun02
프로시저를 실행합니다.
execute del_ename('SCOTT');
해당 유저 데이터만 삭제 됩니다.
5. IN, OUT, INOUT 매개 변수 1) IN 매개 변수 입력만 가능한 매개 변수 입니다.
create or replace procedure del_ename(vename emp_cp02.ename%TYPE) 는 create or replace procedure del_ename(vename IN emp_cp02.ename%TYPE) 지정하지 않으면 기본값이 IN 매개변수로 지정됩니다.
2) OUT 매개 변수 ed fun03
create or replace procedure sel_empno ( vempno IN emp.empno%TYPE, vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE ) is begin select ename, sal, job into vename, vsal, vjob from emp where empno = vempno; end; /
저장하고 프로시저를 생성하기 위해 PL/SQL 문을 실행합니다. @fun03
바인드 변수 선언 variable var_ename VARCHAR2(15); variable var_sal NUMBER; variable var_job VARCHAR2(9); 저장 프로시저를 활용합니다.
6. 저장 함수 저장 함순는 저장 프로시저와 거의 유사한 용도로 사용됩니다. 차이점 : 함수는 실행 결과를 되돌려 받을수 있습니다.
1) PL/SQL 작성 ed fun04
create or replace function cal_bonus
( vempno IN emp.empno%TYPE ) return NUMBER is vsal NUMBER(7, 2); begin select sal into vsal from emp where empno=vempno;
return (vsal * 200); end; /
위의 선언문중 return NUMBER 라는 부분을 반드시 기억해 두어야 합니다. 리턴 타입이 숫자라는 것이죠...
2) PL/SQL 실행하여 저장 함수 생성 @fun04
3) 저장함수 호출 저장할 변수 선언
variable var_x NUMBER;
함수 호출 execute :var_x := cal_bonus(7788);
결과 출력 print var_x;
4) 저장 함수를 호출하는 문장을 SQL문에 포함 select sal, cal_bonus(7788) from emp where empno=7788;
1. 패키지 생성과 실행
ed pack01
create or replace package exam_pack is
procedure sel_empno ( vempno IN emp.empno%TYPE, vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE );
function cal_bonus ( vempno IN emp.empno%TYPE ) return NUMBER; end; /
show errors
create or replace package body exam_pack is procedure sel_empno ( vempno IN emp.empno%TYPE, vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE ) is begin select ename, sal, job into vename, vsal, vjob from emp where empno=vempno; end;
function cal_bonus ( vempno IN emp.empno%TYPE ) return NUMBER is vsal NUMBER(7, 2); begin select sal into vsal from emp where empno=vempno;
return (vsal * 200); end; end; /
show errors
@pack01
package 정의 부와 body 부분이 모두 오류가 없어야 합니다.
패키지 실행부 만들기
ed exe01
set serveroutput on;
create or replace procedure demo_procedure ( vempno IN emp.empno%TYPE ) is var_ename VARCHAR2(15); var_sal NUMBER; var_job VARCHAR2(9); var_bonus NUMBER; begin exam_pack.sel_empno(vempno, var_ename, var_sal, var_job);
create or replace package exam_pack2 is gempno NUMBER(4); /* 전역 변수 */ procedure sel_empno ( vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE );
procedure sel_empno ( vempno IN emp.empno%TYPE,
vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE ); end; /
show errors
create or replace package body exam_pack2 is procedure sel_empno ( vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE ) is begin select ename, sal, job into vename, vsal, vjob from emp where empno=gempno; /* 전역 변수에 저장된 사원번호로 조회 */ end;
procedure sel_empno ( vempno IN emp.empno%TYPE, vename OUT emp.ename%TYPE, vsal OUT emp.sal%TYPE, vjob OUT emp.job%TYPE ) is begin select ename, sal, job into vename, vsal, vjob from emp where empno=vempno; end;
begin /* ONE-TIMR-ONLY 프로시저로서 전역 변수 gempno에 초기값을 설정합니다. */ select empno into gempno from emp where ename='SCOTT'; end; /
show errors
@pack02
package 정의 부와 body 부분이 모두 오류가 없어야 합니다.
패키지 실행부 만들기
ed exe02
set serveroutput on;
create or replace procedure demo_procedure2 ( vempno IN emp.empno%TYPE ) is var_ename VARCHAR2(15); var_sal NUMBER; var_job VARCHAR2(9); var_bonus NUMBER; begin exam_pack2.sel_empno(vempno, var_ename, var_sal, var_job);
var_bonus := exam_pack2.cal_bonus(vempno);
dbms_output.put_line('name sal job bonus '); dbms_output.put_line(var_ename||' '||var_sal||' '||var_job); end; /
show errors;
execute demo_procedure2(7788)
저장하고
실행 합니다. @exe02
오류가 없다면 name sal job SCOTT 3000 ANALYSY name sal job SCOTT 3000 ANALYSY
의 결과가 출력 됩니다.
3. DBMS_OUTPUT 패키지 dbms_output.put_line(String);
conn system/manager select object_name from dba_objecs where object_type='PACKAGE' and object_name like 'DBMS_%' order by object_name;
결과 OBJECT_NAME -----------------
DBMS_OFFLINE_UTL DBMS_OUTPUT
desc DBMS_OUTPUT
dbms_output. 에 올수 있는 프로시저명 정리
DISABLE 화면에 문자열을 출력하는 모드를 해제 ENABLE 화면에 문자열을 출력하는 모드를 설정 GET_LINE/GET_LINES 현재 라인에서 입력한 값을 읽어감 NEW_LINE GET_LINE에서 읽혀진 행의 다음 라인을 읽음 PUT/PUT_LINE 주어진 데이터를 화면에 출력함
3) 자료 입력과 데이터 확인 테이블들이 제대로 생성되었는지 확인합니다. desc item; desc warehousing;
자료 입력
insert into item values ('A00001', 'item1', 'LG', 500, 0); insert into item values ('A00002', 'item2', 'TG', 700, 0); insert into item values ('A00003', 'item3', 'SK', 600, 0);
자료 확인
select * from item;
4) 입고 트리거 작성과 테스트
ed wtrg
create or replace trigger trg02
after insert on warehousing for each row DECLARE v_cnt NUMBER; BEGIN select count(*) into v_cnt from item where idx = :new.itemcode;
if v_cnt = 0 then insert into item(idx, stock) values (:new.itemcode, :new.wstock); else update item set stock = stock + :new.wstock where idx = :new.itemcode; end if; END; /
// 입고트리거 스크립트 실행 @wtrg
Warning: Trigger created with compilation errors. 에러가 발생하면..
show errors trigger trg02 실행하면 트리거에 관련된 오류메시지를 보여 줍니다.
// 자료 입력
isnert into warehousing values (1, 'A00001', '20090823', 5, 320, 1600); select * from warehousing; select * from item;
isnert into warehousing values (2, 'A00002', '20090823', 10, 600, 6800); select * from warehousing; select * from item;
insert into warehousing values (3, 'A00003', '20090823', 3, 220, 660); insert into warehousing values (4, 'A00003', '20090823', 5, 220, 1100);
select * from item; select * from warehousing order by widx;
5) 갱신 트리거 이미 입고된 상품에 대해서 입고 수량이 변경되면 상품 테이블의 재고 수량 역시 변경되어야 합니다.
ed trg03
create or replace trigger trg03 after update on warehousing for each row begin update item set stock = stock + (-:old.wstock+:new.wstock) where idx = :new.itemcode; end; /
@trg03
update warehousing set wstock=10, wprice=2000 where widx=3;
select * from warehousing order by widx;
select * from item;
6) 삭제 트리거
입고 테이블에서 입고되었던 상황이 삭제되면 상품 테이블의 재고수량에서 삭제된 입고수량 만큼을 빼는 트리거 작성.
ed trg04
create or replace trigger trg04 after delete on warehousing for each row begin update item set stock = stock - :old.wstock where idx = :old.itemcode; end; /