테이블 설계,컬럼결정,타입을 정함,관계정의
논리적설계(개체,Entity,속성(Attribute))
물리적설계(테이블,컬럼)-타입이 결정된다
ER-WIN -> ERD(ENtity Relation Diagran)
관계 형태를 그림으로 그리면 PK와 FK 확인할 수 있다
PK와 FK 통해서 상속관계 증명(주는 쪽과 받는 쪽 결정)
SELECT
컬럼명1,컬럼명2,...함수명(컬럼명3)
FROM
집합1,집합2,(SELECT문-인라인뷰)
WHERE
컬럼명1=값(상수만 있는 게 아니라 SELECT문도 가능하다-서브쿼리)-조건검색만 가능한 게 아니라 조인도 한다
AND
컬럼명2=값(SELECT문)-교집합:원소가 줄어든다-경우의 수가 줄어든다(속도가 빨라진다)
OR
컬럼명3=값(IN을 대신 썼었다)
: OR을 쓰게 되면 합집합->경우의 수가 자꾸 증가한다(일량이 늘어나서 잘 안 쓴다)
오라클에 OR이 있지만 잘 안 쓰는 것처럼, char타입(hello___:고정형)이 있지만 varchar2(hello나머지칸 반납:가변형)타입을 쓴다
: WHERE char=varchar2 -> false가 나옴 - 논리적 에러. 흐름이 바뀐다
GROUP BY
컬럼명1,컬럼명2(단,그룹함수가 아니다/group by절에 없는 컬럼을 썼을 때 문제가 되니 잘 해결해야 한다)
[[Having]]
ORDER BY
--문제:ename과 sum(sal)은 다른 타입이라 같이 쓸 수 없다
SELECT ename,sum(sal)
FROM emp;
--해결방법1:ename 타입 맞춰주기
SELECT max(ename),sum(sal)
FROM emp;
--해결방법2:그룹으로 묶기
SELECT ename,sum(sal)
FROM emp
GROUP BY ename;
--업무에 대한 복잡도가 높을 수록
--GROUP BY절에 여러 개의 조건이 온다
SELECT deptno,job
FROM emp
GROUP BY deptno,job
ORDER BY deptno;
SELECT decode(job,'CLERK',sal,null)
FROM emp;
--sum을 할 때 null은 계산하지 않는다
SELECT sum(decode(job,'CLERK',sal,null))
FROM emp;
SELECT count(empno),count(comm) FROM emp;

temp 테이블의 사원이름을 한 행에 사번, 성명을 3명씩 보여주시오
--20명 줄을 세운다
SELECT rownum rno FROM temp;
--이름을 나타내고
SELECT rownum rno,emp_name FROM temp;
--1,2,3이 모두 1이 출력되도록 한다
--왜? 3개 이름은 모두 첫 줄에 출력해야 하니까
SELECT
rno,ceil(rno/3)cno
FROM (
SELECT rownum rno FROM temp
);
--mod함수 사용
SELECT
rno,ceil(rno/3)cno,mod(rno,3)mno
FROM (
SELECT rownum rno FROM temp
);
--이름 넣어주기
SELECT
rno,ceil(rno/3)cno,mod(rno,3)mno
,emp_name
FROM (
SELECT rownum rno,emp_name FROM temp
);
--GROUP BY 적용
--왜 7이 나왔을까? 20/3=6.xxxx -> 7
SELECT
ceil(rno/3)cno
FROM (
SELECT rownum rno FROM temp
)
GROUP BY ceil(rno/3)
ORDER BY cno;
참고그림

--참고 그림을 만들려면 어떻게 해야 할까?
--1.아래가 아니라 옆으로 컬럼이 늘어나고 있다
--2.패턴이기 때문에 전체적인 틀을 잡아보는 것
SELECT '김길동','홍길동','박문수' FROM dual
UNION ALL
SELECT '정도령','이순신','지문덕' FROM dual
--그림에서 김길동,null,null 만들어주기 위해 decode 사용
DECODE(mod(rno,3),1,'김길동')
SELECT
ceil(rno/3)cno
,max(DECODE(MOD(rno,3),1,MOD(rno,3)))d1
,max(DECODE(MOD(rno,3),2,MOD(rno,3)))d2
,max(DECODE(MOD(rno,3),0,MOD(rno,3)))d3
FROM (
SELECT rownum rno FROM temp
)
GROUP BY ceil(rno/3)
ORDER BY cno;
<정답>
SELECT
ceil(rno/3)cno
,max(DECODE(MOD(rno,3),1,emp_id))||'_'||max(DECODE(MOD(rno,3),1,emp_name))
,max(DECODE(MOD(rno,3),2,emp_id))||'_'||max(DECODE(MOD(rno,3),2,emp_name))
,max(DECODE(MOD(rno,3),0,emp_id))||'_'||max(DECODE(MOD(rno,3),0,emp_name))
FROM (
SELECT rownum rno,emp_id,emp_name FROM temp
)
GROUP BY ceil(rno/3)
ORDER BY cno;
<3명이 아닌 5명씩 정렬>
SELECT
ceil(rno/5)cno
,max(DECODE(MOD(rno,5),1,emp_id))||'_'||max(DECODE(MOD(rno,5),1,emp_name))
,max(DECODE(MOD(rno,5),2,emp_id))||'_'||max(DECODE(MOD(rno,5),2,emp_name))
,max(DECODE(MOD(rno,5),3,emp_id))||'_'||max(DECODE(MOD(rno,5),3,emp_name))
,max(DECODE(MOD(rno,5),4,emp_id))||'_'||max(DECODE(MOD(rno,5),4,emp_name))
,max(DECODE(MOD(rno,5),0,emp_id))||'_'||max(DECODE(MOD(rno,5),0,emp_name))
FROM (
SELECT rownum rno,emp_id,emp_name FROM temp
)
GROUP BY ceil(rno/5)
ORDER BY cno;
1. natural join
SELECT empno,ename,dname
FROM emp;
SELECT empno,ename,dname
FROM emp,dept; --카타시안의 곱
SELECT empno,ename,dname
FROM emp NATURAL JOIN dept;
--alias 적용
SELECT a.empno,a.ename,b.dname
FROM emp a NATURAL JOIN dept b;
--이런 표현식도 있었음
SELECT empno,ename,dname
FROM emp a NATURAL JOIN dept b
ON a.deptno = b.deptno;
--구 표현식
SELECT empno,ename,dname
FROM emp dept
WHERE emp.deptno = dept.deptno;
연습문제
tcom의 work_year = '2001'인 자료와 temp를 사번으로 연결해서 join한 후, comm을 받는 직원의 성명, salary + COMM을 조회해 보시오.
SELECT
a.emp_id,a.emp_name,100+10
FROM temp a;
<정답>
SELECT
a.emp_id,a.emp_name,a.salary+b.comm
FROM temp a, tcom b
WHERE a.emp_id = b.emp_id
AND b.work_year = '2001';
<정답-NATURAL JOIN>
SELECT
emp_id,emp_name,salary+comm
FROM temp NATURAL JOIN tcom
WHERE work_year = '2001';
2. non-equai join
연습문제
SELECT
a.emp_id,a.emp_name
FROM temp a,emp_level b
WHERE b.lev ='과장';
SELECT count(emp_id) FROM temp WHERE lev='과장';
<정답>
SELECT
a.emp_id,a.emp_name,a.lev
FROM temp a,emp_level b
WHERE b.lev ='과장'
AND a.salary between from_sal and to_sal;
3. Outer Join
SELECT deptno FROM emp
INTERSECT
SELECT deptno FROM dept;
SELECT deptno FROM emp
MINUS
SELECT deptno FROM dept;
SELECT deptno FROM dept
MINUS
SELECT deptno FROM emp;
SELECT distinct(deptno) FROM emp;
SELECT empno,deptno,dname
FROM emp,dept
WHERE emp.deptno(+)=dept.deptno;
연습문제. 수습사원 내용까지 보여주기
--옛날 outer join 쓰던 방법
--더 보여줘야 하는 쪽에 +를 붙인다
SELECT
b.emp_id 사번
,b.emp_name 성명
,b.salary 연봉
,a.from_sal 하한
,a.from_sal 상한
FROM emp_level a,temp b
WHERE a.lev(+) = b.lev;
4. self join

연습문제
tdept테이블에 자신의 상위 부서 정보를 관리하고 있다. 이 테이블을 이용하여 부서코드, 부서명, 상위부서코드, 상위부서명을 읽어오는 쿼리를 만들어 보자.
--다 나옴. 다 나오는 게 아니라 상위부서만 나와야 함
SELECT
dept_name
FROM tdept;
--상위부서 이름이 나와야하는데 그렇지 않다
SELECT
dept_name,parent_dept
FROM tdept;
--이렇게도 아니다
SELECT
a.dept_name as "부서명"
,b.dept_name as "상위부서명"
FROM tdept a,tdept b;
SELECT
a.dept_name as "부서명"
,b.dept_name as "상위부서명"
FROM tdept a,tdept b
WHERE a.parent_dept = b.dept_code;
<정답>
SELECT
a.dept_code as "부서코드"
,a.dept_name as "부서명"
,b.dept_code as "상위부서코드"
,b.dept_name as "상위부서명"
FROM tdept a,tdept b
WHERE a.parent_dept = b.dept_code;
PL/SQL이란?
PL/SQL의 장점
출처: http://www.gurubee.net/lecture/1039
SQL 실행 - 프롬프트 순서
--출력하는 프로시저
declare
a number(5);
begin
dbms_output.put_line('hello oracle');
dbms_output.put_line('오늘은'||to_char(sysdate,'YYYY-MM-DD')||'입니다.');
end;
/
--Procedure created
--in-외부로 내보낼 수 있음
--IS-변수로 선언한다 / a number(5):=0;-초기화 /
create or replace procedure proc_hello(x IN NUMBER,msg OUT VARCHAR2)
IS
a number(5):=0;
begin
dbms_output.put_line('hello oracle');
dbms_output.put_line('오늘은'||to_char(sysdate,'YYYY-MM-DD')||'입니다.');
end;
/
create or replace procedure proc_hello(x IN NUMBER,msg OUT VARCHAR2)
IS
a number(5):=0;
begin
msg:='오늘은'||to_char(sysdate,'YYYY-MM-DD')||'입니다.';
dbms_output.put_line('hello oracle');
dbms_output.put_line('오늘은'||to_char(sysdate,'YYYY-MM-DD')||'입니다.');
end;
/
msg 내용 확인 방법(프롬프트)
--1부터 10까지 합 구하는 프로시저
create or replace procedure proc_hap(num in number,msg out varchar2)
is
n_i number(5):=0;
n_hap number(5):=0;
begin
for n_i in 1..10 loop
n_hap :=n_hap+n_i;
end loop;
msg :='1부터 10까지의 합은 '||n_hap||'입니다.';
end;
<프롬프트>
exec proc_hap(1,:msg);
SQL> print msg
--1부터 100까지 세면서 5의 배수의 합
create or replace procedure proc_hap2(msg out varchar2)
is
n_i number(5):=0;
n_hap number(5):=0;
begin
for n_i in 1..100 loop
if mod(n_i,5)=0 then
n_hap := n_hap + n_i;
end if;
end loop;
msg :='5의 배수의 합은 '||n_hap||'입니다.';
end;
*else if가 아니라 elsif임
-- 5의 배수일 때 fizz 출력 / 7의 배수일 때 buzz 출력
-- 5,7의 공배수일 때 fizzbuzz 출력
create or replace procedure proc_hap3(msg in varchar2)
is
n_i number(5):=0;
begin
for n_i in 1..100 loop
if mod(n_i,35)=0 then
dbms_output.put_line('fizzbuzz');
elsif mod(n_i,5)=0 then
dbms_output.put_line('fizz');
elsif mod(n_i,7)=0 then
dbms_output.put_line('buzz');
else
dbms_output.put_line(n_i);
end if;
end loop;
end;
begin
proc_hap3('');
end;
-- 3을 입력하면 3단 출력, 5를 입력하면 5단 출력(구구단)
CREATE OR REPLACE PROCEDURE proc_gugudan(dan in number)
IS
n_i number(2);
BEGIN
n_i:=0;
dbms_output.put_line(dan||'단을 출력합니다.');
for n_i in 1..9 loop
dbms_output.put_line(dan||'*'||n_i||'='||(dan*n_i));
end loop;
END ;
/
<test>
begin
proc_gugudan(5);
end;
<test>
exec proc_gugudan(9);
연습문제
SQL4장(t_worktime)

SELECT * FROM t_worktime;
이 데이터의 작업시간이 짧게 걸리는 시간 순서대로 1부터 15까지의 순위를 매겨서 출력하시오. (그림예시)

--오라클에서 쓰는 함수
SELECT
workcd_vc,time_nu
,rank()over(order by time_nu)rnk
FROM t_worktime;

--데이터 3개만 뽑아서 써보자
SELECT rownum rno,workcd_vc,time_nu FROM t_worktime
WHERE rownum < 4;
------------------------------------------
SELECT
*
FROM (
SELECT rownum rno,workcd_vc,time_nu FROM t_worktime
WHERE rownum < 4
)a,
(
SELECT rownum rno,workcd_vc,time_nu FROM t_worktime
WHERE rownum < 4
)b;
------------------------------------------
SELECT
a.workcd_vc,a.time_nu,count(b.workcd_vc)
FROM (
SELECT rownum rno,workcd_vc,time_nu FROM t_worktime
WHERE rownum < 4
)a,
(
SELECT rownum rno,workcd_vc,time_nu FROM t_worktime
WHERE rownum < 4
)b
WHERE a.time_nu >= b.time_nu
GROUP BY a.workcd_vc,a.time_nu;
함수와 프로시저
--예시.함수는 반환값이 꼭 있다
SELECT mod(5,2),substr('hello',2),sign(100-500)
FROM dual;
--tmp 변수에 담았다
create or replace procedure proc_dept(x in number)
is
tmp varchar2(20);
begin
SELECT dname INTO tmp
FROM dept
WHERE deptno = x;
dbms_output.put_line(tmp);
end;
<test>
begin
proc_dept(10);
end;
-----------------------
begin
proc_dept(20);
end;
create or replace procedure proc_dept(x in number)
is
vdname varchar2(20);
vloc varchar2(30);
begin
SELECT dname,loc INTO vdname,vloc
FROM dept
WHERE deptno = x;
dbms_output.put_line(vdname||','||vloc);
end;
<test>
begin
proc_dept(30);
end;