-- Q) 직원의 이름, 급여와 부서명을 출력하시오.
SELECT frist_name 이름, salary 급여, department_name 부서명
FROM employees, departments;
-- 답은 나왔지만 오답이다.
-- cartesian product
-- join :
(1) 테이블을 2개 이상
(2) pk = fk
SELECT first_name 이름, salary 급여, department_name 부서명
FROM employees, departments
WHERE department_id = department_id; -- pk=fk
-- 테이블명.칼럼명
-- join (equi join)
-- oracle join vs ansi1999
--web document.all document.getElementById()
-- IE
-- ANSI , ISO/IEC 1992, 1999
-- oracle join
-- equi join , non-equi join, self-join, outer join
-- Q) 직원의 이름, 매니저아이디, 지역아이디를 조회 출력하시오
-- (단, 이름순으로 정렬)
SELECT e.first_name 이름, e.manager_id 메니저아이디, d.location_id 지역아이디
FROM employees e, departments d
WHERE e.department_id =d.department_id
order by 1;
-- Q) 직원의 이름, 매니저아이디, 지역아이디를 출력하시오.
-- 단, manager_id가 120이상인 경우만
-- (단, 이름순으로 정렬)
SELECT e.first_name 이름, e.manager_id 매니저아이디, d.location_id 지역아이디
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND e.manager_id >=120
--where employees.department_id = departments.department_id;
order by 1;
-- Q) 전체 사원의 이름과 직책(job_title)을 조회 출력하시오.
SELECT e.first_name 사원명, j.job_title 직책
FROM employees e, jobs j
WHERE e.job_id = j.job_id
ORDER BY 1;
-- Q) 전체 직원의 이름, 부서명, 해당 city를 조회 출력하시오.
-- (단, city 오름차순으로)
SELECT e.first_name 이름, d.department_name 부서명, l.city 도시명
FROM employees e, departments d, locations l
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id
ORDER BY 3;
-- Q) 도시별 사원수를 조회 출력
SELECT l.city 도시명, COUNT(*) 사원수
FROM employees e, departments d, locations l
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id
GROUP BY l.city;
-- Q) 부서이름과 해당 부서가 속한 도시명(city)을 조회출력하시오.
SELECT d.department_name 부서이름, l.city 도시명
FROM departments d, locations l
WHERE d.location_id = l.location_id;
-- Q) 사원의 이름과 해당 사원이 근무하는 국가명을 조회출력하시오.
SELECT e.first_name 이름, c.country_name 국가명
FROM employees e, departments d, locations l, countries c
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id
AND l.country_id = c.country_id
ORDER BY 1;
-- Q) 직책(job_title)이 'representative' 인 사람의 이름, 직책, 부서명을 조회 출력하시오.
-- Sales representative(판매직원), Public Relations Representative(홍보직원)
-- (cf) 대표 : president, 대표이사 : CEO, 과대표 : class representative
-- (cf) 테이블의 JOIN시 sql tunning을 생각해볼 때
-- driving table
SELECT e.first_name 이름, j.job_title 직책, d.department_name 부서명
FROM jobs j, employees e, departments d
WHERE e.job_id = j.job_id
AND e.department_id = d.department_id
AND LOWER(j.job_title) like '%representative%'
ORDER BY 1;
-- Q) 직책(job_title)이 'clerk'인 사람의 이름, 직책, 부서명을 조회출력하시오.
SELECT e.first_name 이름, j.job_title 직급, d.department_name 부서명
FROM jobs j, employees e, departments d
WHERE e.job_id = j.job_id
AND e.department_id = d.department_id
AND LOWER(j.job_title) LIKE '%clerk%';
-- Q) 도시별로 그리고 같은 도시일 경우 다시 부서명별로 묶어 2008년까지 입사한 사원수를
-- 조회하여 출력하시오. 출력은 도시이름, 부서명 해당 사원수를 출력하며
-- 만일 출력시 도시이름 오름차순으로 정렬하되 같은 도시이면 사원이 많은 순부터 출력하시오.
SELECT l.city 도시명, d.department_name 부서명, count(*) "부서 사원수"
FROM departments d, locations l, employees e
WHERE e.department_id = d.department_id AND d.location_id = l.location_id
AND SUBSTR(e.hire_date, 1 ,2) <=08
GROUP BY l.city, d.department_name
ORDER BY 1 ASC, 3 DESC;
-- Q) 직책명(job_title)이 ‘Sales’로 시작하는
-- 직원 중에서 급여(salary)가 10,000 이상, 20,000 이하인 직원들의
-- 이름(first_name), 성(last_name)과 연봉(salary) 및 직책(job_title)을 조회 출력하시오.
-- (단, 급여가 많은 순으로 출력하시오)
SELECT e.first_name 이름, e.last_name 성, e.salary*12 연봉, j.job_title 직책
FROM employees e, jobs j
WHERE e.job_id=j.job_id
AND j.job_title LIKE 'Sales%'
AND e.salary BETWEEN 10000 AND 20000
ORDER BY e.salary DESC;
-- kimberly를 해결하자. 107명 ==> 106명
-- Q) 전체 사원의 이름, 급여, 부서명 출력
SELECT e.first_name 이름,e.salary 급여,d.department_name 부서명
FROM employees e,departments d
WHERE e.department_id = d.department_id;
-- 106명 / equi join pk == fk 특성 때문
□ OUTER JOIN
equi join (pk == fk) + 안 나온 것도 나오게 하는 것.
-- Q) 사원의 이름, 급여, 부서명 출력
-- 단, 부서가 없는 kimberly도 나오게 하시오.
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+);
-- Q) 사원의 이름, 급여, 부서명 출력
-- 단, 사원없이 부서이름만 있는 부서명도 출력하게 하시오.
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
-- Q) 사원의 이름, 급여, 부서명 출력
-- 단, 부서가 없는 kimberly도 나오게하시오
-- 그리고 사원없이 부서이름만 있는 부서명도 출력하게 하시오.
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id(+);
-- 틀린 방법
해결방법 1) (oracle)
집합 : 합집합, 교집합, 차집합
UNION, UNION ALL(중복), INTERSECT, MINUS
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id
UNION ----------------
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+);
해결방법 3) (ANSI)
-- Q) 사원의 이름, 급여, 부서명 출력
-- 단, 부서가 없는 kimberly도 나오게 하시오.
1) ansi 방식
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e LEFT OUTER JOIN departments d -- 이름 나오는 쪽 left
ON (e.department_id = d.department_id);

2) oracle
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+); -- null 나오는 쪽 (+)
-- Q) 사원의 이름 급여 부서명 출력
-- 단, 사원없이 부서이름만 있는 부서명도 출력하게 하시오.
1) ansi 1999
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e RIGHT OUTER JOIN departments d -- 부서명 나오는 쪽 left
ON (e.department_id = d.department_id);
2) oracle
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
-- Q) 사원의 이름, 급여, 부서명 출력
-- 단, 부서가 없는 kimberly도 나오게 하시오.
-- 그리고 사원없이 부서이름만 있는 부서명도 출력하게 하시오.
1) ansi
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);
2) oracle
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id
UNION
SELECT e.first_name 이름, e.salary 급여, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+) ;
-- Q) 2007년 입사한 직원들의 사번, 이름, 성(last_name), 입사일, 부서명을 출력
-- 만일 부서에 배치되지 않은 직원의 경우,
-- ‘그런부서없어’로 보여주고 정렬은 성(last_name) 을 기준 출력
-- 단, 오라클 방식 및 ansi 1999 로 푸시오.
1) oracle
SELECT e.employee_id 사번, e.first_name 이름, e.last_name 성, e.hire_date 입사일, NVL(d.department_name, '그런부서없어') 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+)
AND e.hire_date LIKE '07%'
ORDER BY last_name;
employees의 부서아이디를 추가로 출력하되 null이면 '없어' 출력
SELECT e.employee_id 사번, e.first_name 이름, e.last_name 성, e.hire_date 입사일, NVL(d.department_name, '그런부서없어') 부서명,
NVL(TO_CHAR(e.department_id), '없어') 부서아이디
FROM employees e, departments d
WHERE e.department_id = d.department_id(+)
AND e.hire_date LIKE '07%'
ORDER BY last_name;
2) ansi
SELECT e.employee_id 사번, e.first_name 이름,
e.last_name 성, e.hire_date 입사일, NVL(d.department_name, '그런부서없어') 부서명
FROM employees e LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id)
WHERE e.hire_date LIKE '07%'
ORDER BY last_name;
그렇다면 WHERE에 있는 조건을 ON 에 추가로 넣으면 어떻게 될까?
SELECT e.employee_id 사번, e.first_name 이름,
e.last_name 성, e.hire_date 입사일, NVL(d.department_name, '그런부서없어') 부서명
FROM employees e LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id AND e.hire_date LIKE '07%')
ORDER BY last_name;
-- 문제발생 (PK == FK에서)
-- 즉 department_id == (department_id and 2007년)
-- Q) 사원의 사번, 이름, 매니저 아이디를 조회 출력하시오.
SELECT employee_id 사번, first_name 이름, manager_id 매니저아이디
FROM employees;
-- Q) 사원의 사번, 이름, 매니저이름을 조회 출력하시오
-- 매니저이름 컬럼은 어디에? ==> employees 에 숨어 있음.
-- (별도 컬럼 x)
□ 셀프조인
eqi join + 같은 테이블 2개
SELECT e.employee_id 사번, e.first_name 사원명, m.first_name 매니저이름
FROM employees e, employees m
WHERE e.manager_id = m.employee_id
ORDER BY 1; -- kimbery o, steven x
kimbery는 나오지만, steven은 나오지 않는다. steven의 매니저 아이디는 null이기 때문이다.
따라서
SELECT e.employee_id 사번, e.first_name 사원명, m.first_name 매니저이름
FROM employees e, employees m
WHERE e.manager_id = m.employee_id(+)
ORDER BY 1; -- kimbery o, steven o
다음과 같이 하면 (+) steven의 행도 출력된다.
NVL을 이용해서 null 값을 처리해주면
SELECT e.employee_id 사번, e.first_name 사원명, NVL(m.first_name, '매니저없음') 매니저이름
FROM employees e, employees m
WHERE e.manager_id = m.employee_id(+)
ORDER BY 1;
-- Q) 매니저이름과 해당 매니저가 관리하는
-- 사원의 수를 출력하시오.
-- (단, 관리되는 사원수가 5명 이상인 관리자만 조회 출력)
실습용 테이블 생성
CREATE TABLE tel77(
sabun NUMBER(5),
irum VARCHAR2(20),
tel VARCHAR2(20),
salary NUMBER(7)
);
INSERT INTO tel77
VALUES (1,'hong','010-777-8888',5000000);
INSERT INTO tel77
VALUES (2,'choi','010-5555-8888',3000000);
COMMIT;
-- Q) 전사원의 급여를 10% 인상
UPDATE tel77
SET salary = salary * 1.1;
'hong' 이름 변경
UPDATE tel77
SET irum = 'park'
WHERE irum = 'hong';
commit;
UPDATE tel77
SET salary = salary * 1.2; -- 아직 db로 x
rollback;
-- 롤백, 세이브포인트 연습
SELECT * FROM tel77;
UPDATE tel77
SET salary = salary * 1.3;
SAVEPOINT yoki;
INSERT INTO tel77(sabun)
VALUES (10);
SELECT * FROM tel77;
SAVEPOINT jeoki;
ROLLBACK yoki;
COMMIT;
-- Q) 사원의 봉급 인상
-- 직책에 'Manager'가 있으면 10%인상
-- 그외는 20% 인상
-- (출력은 이름, 직책, 봉급, 인상된봉급)
자바의 경우에는 if-else 사용
SQL에서는 decode()를 사용
□ DECODE
DECODE(대상칼럼, 조건, yes처리1, no처리2)
-- 예) DECODE(salary, 10000, salary * 1.1, salary * 1.2)
-- 과정1)
SELECT e.first_name 이름, j.job_title 직책, e.salary 봉급
FROM employees e, jobs j
WHERE e.job_id = j.job_id;
-- 과정2)
SELECT e.first_name 이름, j.job_title 직책, e.salary 봉급,
DECODE(SUBSTR(job_title, -7), 'Manager', salary * 1.1, salary * 1.2) 인상된봉급
FROM employees e, jobs j
WHERE e.job_id = j.job_id;
-- Q) 사원의 봉급 인상
-- 직책에 'Manager'가 있으면 10% 인상 Accountant 20% , 그외는 30%
-- 그외는 20% 인상
-- (출력은 이름, 직책, 봉급, 인상된봉급)
-- (step3) case - when
case when - then -
when - then -
when - then -
else
end
SELECT e.first_name 이름, j.job_title 직책, e.salary 봉급,
CASE WHEN SUBSTR(job_title, -7) = 'Manager' THEN e.salary * 1.1
WHEN SUBSTR(job_title, -7) = 'ountant' THEN e.salary * 1.2
ELSE e.salary * 1.3
END AS 인상된봉급
FROM employees e, jobs j
WHERE e.job_id = j.job_id;
-- Q) 직원의 사번, 사원명, 매니저이름을 출력
-- (단, 매니저가 없는 직원도 출력. 출력형태는 '매니저없어!!!', union사용)
-- 1) steven 없이 (self join 사용)
SELECT e.employee_id 사번, e.first_name 사원명, m.first_name 매니저이름
FROM employees e, employees m
WHERE e.manager_id = m.employee_id;
-- 2) steven 을 해결
SELECT employee_id 사번, first_name 사원명, '매니저없어!!!'
FROM employees
WHERE manager_id IS NULL;
-- 3) 두개를 합쳐서 실행, union (union all, union distinct)
SELECT e.employee_id 사번, e.first_name 사원명, m.first_name 매니저이름
FROM employees e, employees m
WHERE e.manager_id = m.employee_id
UNION
SELECT employee_id 사번, first_name 사원명, '매니저없어!!!'
FROM employees
WHERE manager_id IS NULL;
-- Q) 직원의 사번, 사원명, job아이디 조회 출력
-- (단, job_id가 'Clerk'이 들어간 사원은 제외하시오.)
차집합 (minus) 사용
SELECT employee_id 사번, first_name 사원명, job_id job아이디
FROM employees -- 107명
MINUS
SELECT employee_id 사번, first_name 사원명, job_id job아이디
FROM employees
WHERE LOWER(job_id) LIKE '%clerk%'; -- 45명
□ 실습
DROP TABLE SALGRADE;
CREATE TABLE SALGRADE(
GRADE NUMBER(5) NOT NULL,
LSAL NUMBER(8),
HSAL NUMBER(8),
CONSTRAINT SALGRADE_GRADE_PK PRIMARY KEY(GRADE)
);
INSERT INTO SALGRADE(GRADE, LSAL, HSAL) VALUES(1, 500, 2999);
INSERT INTO SALGRADE(GRADE, LSAL, HSAL) VALUES(2, 3000, 3799);
INSERT INTO SALGRADE(GRADE, LSAL, HSAL) VALUES(3, 3800, 5899);
INSERT INTO SALGRADE(GRADE, LSAL, HSAL) VALUES(4, 5900, 9999);
INSERT INTO SALGRADE(GRADE, LSAL, HSAL) VALUES(5, 10000, 70000);
COMMIT;
-- Q) 급여가 3800인 사원의 급여등급을 조회출력하시오.
SELECT grade 급여등급
FROM salgrade
WHERE lsal = 3800;
-- 문제발생
24000 달러의 등급은 어떻게 표시할 것인가?
SELECT grade 급여등급
FROM salgrade
WHERE lsal >= 10000 AND hsal <= 70000;
-- non-equi join
-- Q) 직원의 급여가 몇등급인지를 조회 출력하시오(출력은 이름, 급여, 등급)
-- (단, 급여가 많은순부터, 같은급여면 이름 오름차순부터)
SELECT e.first_name 이름, e.salary 급여, s.grade 등급
FROM employees e, salgrade s
WHERE e.salary BETWEEN s.lsal AND s.hsal
ORDER BY e.salary DESC, e.first_name;
-- Q1) 사원들의 이름과 해당 부서명을 조회 출력하시오.
SELECT e.first_name 사원명, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id
ORDER BY 1;
-- Q2) 사원들의 이름과 해당 부서명을 조회 출력하시오.
-- 단, 담당부서명이 없는 사람도 출력하시오.
SELECT e.first_name 사원명, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+)
ORDER BY 1;
-- Q3) 사원들의 이름과 담당 부서명을 조회 출력하시오.
-- 단, 사원이 없는 부서명도 출력하시오.
SELECT e.first_name 사원명, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id
ORDER BY 1;
-- Q4) 사원들의 이름과 부서명을 조회 출력하시오.
-- 단, 사원이 없는 부서명도 출력하시오.
-- 단, 사원이 없는 곳에 NULL이 아니라 '사원이 없다는~' 글 출력.
SELECT NVL(e.first_name, '사원이 없다는~') 사원명, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id
ORDER BY 1;
-- Q5) 사원들의 이름과 부서명을 조회 출력하시오.
-- 단, 사원이 없는 부서명도 출력하시오.
-- 단, 부서명이 없는 사원도 출력하시오.
SELECT e.first_name 이름, e.last_name 성, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id
UNION
SELECT e.first_name 이름, e.last_name 성, d.department_name 부서명
FROM employees e, departments d
WHERE e.department_id = d.department_id(+)
ORDER BY 1;
SELECT e.first_name 이름, e.last_name 성, d.department_name 부서명
FROM employees e FULL OUTER JOIN departments d
ON (e.department_id = d.department_id)
ORDER BY 1;