SQL - DAY 6

BUMSOO·2024년 6월 17일

정규화(Normalization)

  • 데이터에 대한 중복성을 제거
  • 데이터 정합성(데이터의 정확성과 일관성을 유지 하고 보장)을 위해 table(entity)을 작은 단위로 분리하는 과정
  • 입력,수정,삭제 이상현상(anomaly)현상 발생을 최소화

JOIN

  • 두개이상의 테이블에서 내가 원하는 데이터를 가져오는 기법

CARTESIAN PRODUCT

  • 조인 조건이 생략된 경우
  • 조인 조건이 잘못 만든 경우
  • 첫번째 테이블 행의 수와 두번째 테이블의 행 수가 곱해진다
SELECT employee_id, last_name, department_name
FROM hr.employees, hr.departments;

EQUI JOIN, INNER JOIN, SIMPLE JOIN, 등가조인

  • 조인 키값이 일치하는 데이터만 추출하는 조인

<주의사항>
1) 양쪽 테이블의 동일한 이름의 컬럼을 사용해서 조인조건 술어를 만들게 되면 컬럼의 정의가 모호하다라는 오류가 발생한다.

2) 해결 방법은 컬럼 이름앞에 테이블 이름 또는 테이블 별칭을 접두어로 붙이자
3) 테이블 별칭을 사용해서 컬럼 정의의 모호성을 해결하는게 좋다. 이유는 메모리 사용량을 줄일 수 있다.

SELECT
    employee_id,
    last_name,
    d.department_id,
    department_name
FROM
    hr.employees      e, --테이블에 별칭(as사용 불가)
    hr.departments    d -- as는 열별칭에만 사용 가능
WHERE
    e.department_id = d.department_id; -- 조인조건 술어
    --M쪽 집합(107)   1쪽집합(27) 
    --조인 결과는 M쪽 집합에 있는 행의 수만큼 나오면 된다.

N개의 테이블을 조인하려면 조인조건술어는 N-1개의 조인조건 술어를 작성해야 한다.

SELECT e.employee_id, l.city
FROM hr.employees e, hr.depart	ments d,  hr.locations l
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id;

[문제30]

80번 부서에 근무하는 사원들의 last_name, job_id, department_name, city 출력해주세요

<풀이>

SELECT
    a.last_name,
    a.job_id,
    b.department_name,
    c.city
FROM
         hr.employees a
    JOIN hr.departments b ON a.department_id = b.department_id
    JOIN hr.locations c ON b.location_id = c.location_id
WHERE
    a.department_id = 80;

조건절 이행

a=b 이고 b=c 면 a=c추론

<해당 쿼리의 실행계획>

WHERE a.department_id = 80
AND b.department_id = 80
AND b.location_id = c.location_id;

오라클 내부적으로 실행계획을 employees테이블 M집합,
departments 테이블 1집합으로 만든뒤 cartesian 곱을 해버린다. 그렇게 처리하는게 더 빠른 결과물을 보여준다.

[문제31]

locations 테이블에 있는 city컬럼에 Toronto도시에서 근무하는 모든 사원의 last_name, job_id, department_id, department_name 출력해주세요

<풀이>

SELECT
    a.last_name,
    a.job_id,
    b.department_id,
    b.department_name
FROM
         hr.employees a
    JOIN hr.departments b ON a.department_id = b.department_id
    JOIN hr.locations c ON b.location_id = c.location_id
WHERE
    c.city = 'Toronto';

OUTER JOIN

  • 키 값이 일치되는 데이터 또는 키 값이 일치되지 않는 데이터도 출력하는 조인
  • 한쪽에만 (+) 표현한다.
  • 양쪽에 (+)를 수행하면 오류발생
    <오류해결방법>
    1) ANSI 표준으로 수행
    2) 집합연산자를 이용
  • (+)이 붙지 않은 테이블 (left,right) join 효과
SELECT e.employee_id, e.last_name, d.department_name,l.city
FROM hr.employees e, hr.departments d ,hr.location l
WHERE e.department_id = d.department_id(+) --hr.employees left join 효과
AND d.location_id = l.location_id(+) --전체 M집합 테이블 left join 효과; 

SELF JOIN

  • 자신의 테이블을 참조할때 사용하는 조인
  • 업무파악이 중요
# 사원 테이블 (work)
SELECT employee_id, last_name, manager_id
FROM hr.employees;

# 관리자 테이블 (manager)
SELECT employee_id, last_name
FROM hr.employees;
# 셀프조인 테이블
SELECT w.employee_id, w.last_name, m.employee_id, m.last_name
FROM hr.employees w, hr.employees m
WHERE w.manager_id = m.employee_id(+);

NON EQUI JOIN

  • equi join (=) 할수 없는 즉 다른 비교연산자를 사용 하는 조인기법
  • 값을 범위로 조인하려는 경우 많이 사용된다.
SELECT
    a.employee_id,
    a.salary,
    b.grade_level
FROM
    hr.employees a,
    hr.job_grades b
WHERE
    a.salary BETWEEN b.lowest_sal AND b.highest_sal;

[문제32]

commission_pct에 null 이 아닌 사원들의 last_name, commission_pct, department_name 을 출력해주세요.

<풀이>

SELECT
    e.last_name,
    e.commission_pct,
    d.department_name
FROM
    hr.employees      e,
    hr.departments    d
WHERE
        e.department_id = d.department_id
    AND e.commission_pct IS NOT NULL;

[문제33]

last_name에 소문자 'a'가 포함된 사원들의 last_name, department_name을 출력해주세요.

<풀이>

SELECT
    e.last_name,
    d.department_name
FROM
    hr.employees      e,
    hr.departments    d
WHERE
        e.department_id = d.department_id
    AND instr(e.last_name,'a',1,1) > 0;

[문제34]

사원들의 급여의 등급 레이블의 빈도수를 출력해주세요.

<풀이>

SELECT
    j.grade_level,
    COUNT(*)
FROM
    hr.employees     e,
    hr.job_grades    j
WHERE
    e.salary BETWEEN j.lowest_sal AND j.highest_sal
GROUP BY
    j.grade_level
ORDER BY
    1;

[문제35]

사원들의 사번, 급여, 급여등급, 부서이름을 출력하세요.
부서배치를 받지 않는 사원은 제외시켜주세요.

<풀이>

SELECT
    e.employee_id,
    e.salary,
    j.grade_level,
    d.department_name
FROM
    hr.employees      e,
    hr.departments    d,
    hr.job_grades     j
WHERE
        e.department_id = d.department_id
    AND e.salary BETWEEN j.lowest_sal AND j.highest_sal;

[문제36]

사원들의 사번, 급여, 급여등급, 부서이름, 근무 도시 정보를 출력하세요.
부서배치를 받지 않는 사원도 포함시켜주세요.

SELECT
    e.employee_id,
    e.salary,
    j.grade_level,
    d.department_name,
    l.city
FROM
    hr.employees      e,
    hr.departments    d,
    hr.locations      l,
    hr.job_grades     j
WHERE
        e.department_id = d.department_id (+)
    AND e.salary BETWEEN j.lowest_sal AND j.highest_sal
        AND d.location_id = l.location_id (+);

[6일차 후기]

오늘은 SQL을 배우면서 가장 헷갈릴 파트인 JOIN절을 배웠다. 나도 이걸 처음 배울때 조인 테이블간의 집합레벨을 확립하지 못해 어려워했던 기억이 있다. 그래서 JOIN절을 공부할때는 ER다이어그램을 보면서 테이블간의 관계를 잘 파악해두지 않으면 JOIN을 제대로 이해하지 못할수도 있다.
오늘 배운 부분중 가장 인상 깊었던 부분은 나는 실제로 JOIN절을 사용하여 JOIN을 했다고 생각했지만 오라클은 내부적으로 조건절 이행을 통해 M:1 카테시안조인을 하여 쿼리문을 작동하는 점이었다. 이렇게 실행계획을 통해 보면 새롭게 알게되는게 많은데 아키텍처를 공부하게 되면 얼마나 새로운걸 배우게 될지 벌써 궁금하다. 오늘 가장 헷갈렸던건 나는 평소 ANSI조인을 통해 OUTER JOIN을 해왔는데 ORACLE 문법으로는 (+)을 사용하는것이었다.

0개의 댓글