정규화(Normalization)은 다양한 정보를 포함하고 있는 하나의 테이블을 각 정보에 맞게 쪼개는 작업을 의미합니다.

따라서, 정규화는 '무손실 분해'라고 합니다.

 

 


 

 

정규화는 각각의 정보를 별도의 릴레이션으로 무손실 분해해서 이상현상을 제거하는 것에 목적을 두고 있습니다.

 

이러한 정규화는 6가지로 나눌 수 있지만 일반적으로 세 종류의 정규화를 주로 사용합니다.

정규화 단계를 거쳐야 다음 정규화 과정을 수행할 수 있습니다.

 

 

# 정규화

 

  1.  1NF 릴레이션
  2.  2NF 릴레이션
  3.  3NF 릴레이션
  4.  BCNF 릴레이션
  5.  4NF 릴레이션
  6.  5NF 릴레이션

 

 

 

1. 제 1정규형(1NF)

 

1NF는 다중값 속성을 제거하는 단계입니다.

즉, 정규화를 수행하는 릴레이션의 모든 속성값이 원자(단일)값을 가지면 1NF라고 합니다.

 

 

2. 제 2정규형(2NF)

 

2NF는 하나의 릴레이션에 두 개의 릴레이션이 종속되어 있다면 분해하는 단계입니다.

즉, 기본키가 아닌 속성이 기본키에 완전 함수 종속일 때 2NF라고 합니다.

 

 

3. 제 3정규형(3NF)

 

비이행적(non-transitive)으로 종속할 때 3NF라고 합니다.

이행적 종속이란 A = B, B = C일때, A = C가 성립되는 함수 종속성입니다.

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

외부 조인  (0) 2023.08.21
그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

OUTER JOIN은 한 쪽 테이블의 모든 행을 기준으로 다른 테이블을 JOIN합니다.

예를 들어, LEFT OUTER JOIN이라면 왼쪽 테이블의 모든 행을 기준으로 오른쪽 테이블을 JOIN합니다.

 

 


 

 

다음은 OUTER JOIN에 대한 쿼리입니다.

 

-- Oracle LEFT OUTER JOIN --

SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e,
  employees m
WHERE
  e.manager_id = m.employee_id (+);
  
 
 
 -- Ansi LEFT OUTER JOIN --
 
SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e LEFT OUTER JOIN employees m -- OUTER 키워드 생략 가능 --
  ON e.manager_id = m.employee_id;

 

RIGHT OUTER JOIN도 동일한 개념으로 동작합니다.

 

 

그런데 Ansi JOIN에서만 있는 FULL OUTER JOIN이 있습니다.FULL OUTER JOIN은 두 테이블의 모든 행을 결합하되, NULL값을 모두 포함하여 결합합니다.

 

-- Ansi FULL OUTER JOIN --

SELECT
  e.last_name AS 사원명,
  e.employee_id AS 사원번호,
  m.last_name AS 관리자명,
  m.employee_id AS 관리자사번
FROM
  employees e FULL OUTER JOIN employees m -- OUTER 키워드 생략 가능 --
  ON e.manager_id = m.employee_id;

 

 

 

 

'Database > SQL' 카테고리의 다른 글

정규화  (0) 2023.09.06
그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

GROUP BY(그룹화)는 SELECT 절에서 집계함수와 단순칼럼이 복합적으로 선택될 때 사용됩니다.

 

 


 

 

1. GROUP BY

 

GROUP BY절은 NULL을 제외하지 않고 그룹화하여 로우의 가장 아래에 생성합니다.

 

먼저 SELECT 절에 스칼라를 선택하는 쿼리를 작성하였습니다.

스칼라는 쿼리의 결과가 하나인 것을 의미합니다.

 

SELECT
    MAX(salary)
FROM
    employees;

 

스칼라

 

결과에서도 알 수 있듯이,

집계함수가 단독적으로 사용된다면 그룹화는 필요 없습니다.

 

 

하지만 집계함수와 단순칼럼이나 표현식이 함께 사용된다면 GROUP BY 절이 사용되야 합니다.

고용된 날짜 별 총 급여를 쿼리로 작성하였습니다.

 

SELECT
    TO_CHAR(hire_date, 'YYYY/MM') AS 고용연월,
    SUM(salary)   AS "총 급여"
FROM
    employees
GROUP BY
    TO_CHAR(hire_date, 'YYYY/MM')
ORDER BY
    1 ASC;

 

위 쿼리는 TO_CHAR를 그룹화하여 해당 고용날짜에 해당하는 사원의 총 급여에 대한 쿼리입니다.

만약 SELECT절에 추가적인 칼럼이나 표현식이 선택되면 GROUP BY절에서 추가적인 그룹화가 필요합니다.

 

 

 

2. HAVING

 

HAVING절은 그룹화와 함께 사용됩니다.

HAVING절은 GROUP BY를 통해 그룹화하고 로우(row, 행)가 아닌 그룹을 제외시킬 수 있습니다.

또한 WHERE절에서는 사용이 불가능한 집계함수를 HAVING절에서는 사용할 수 있습니다.

 

SELECT
    TO_CHAR(hire_date, 'YYYY/MM') AS 고용연월,
    SUM(salary)   AS "총 급여"
FROM
    employees
GROUP BY
    TO_CHAR(hire_date, 'YYYY/MM')
HAVING
    SUM(salary) >= 10000
ORDER BY
    1 ASC;

 

위 쿼리처럼 HAVING절은 집계함수 사용이 가능하며, WHERE절과 같은 그룹에 대한 필터링을 수행합니다.

 

 

 

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

정규화  (0) 2023.09.06
외부 조인  (0) 2023.08.21
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16

 

 

 

인라인 뷰는 기존 테이블에서 필요한 칼럼만 추출 후 일종의 임시 테이블로 사용하는 방식입니다.

 

 


 

 

인라인 뷰를 사용하면 쿼리가 더 간결해지고 중복 코드를 제거할 수 있습니다.

다만, 과도하게 중첩된 인라인 뷰는 쿼리의 복잡도를 높일 수 있기 때문에 주의해야 합니다.

 

 

간단한 예시 코드입니다.

 

SELECT
    부서번호,
    평균월급
FROM
    ( SELECT
          department_id AS 부서번호,
          AVG(salary)   AS 평균월급
      FROM
          employees
      WHERE
          department_id IS NOT NULL
      GROUP BY
          department_id
      ORDER BY
          department_id ASC;
     );

 

위 쿼리에서 FROM 절에 해당하는 부분이 ' 인라인 뷰 ' 입니다.

메인 쿼리인 SELECT 절에서는 인라인 뷰의 쿼리 결과를 별칭을 선택해서 받아왔습니다.

 

 

 

 

'Database > SQL' 카테고리의 다른 글

외부 조인  (0) 2023.08.21
그룹화  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16
크로스 조인  (0) 2023.08.10

 

 

 

FORGEIGN KEY(외래 키 또는 참조 키)는 자식 테이블에서 부모 테이블을 참조할 때,

올바른 데이터만 참조하도록(참조 무결성) 제약합니다.

 

 


 

 

외래 키는 부모 테이블과 자식 테이블 간 참조 무결성을 위한 제약 조건이므로, 

자식 테이블에서 참조하는 칼럼을 부모 테이블에서 PRIMARY KEY 또는 UNIQUE로 설정해야 합니다.

 

 

부모 테이블을 만들고 자식 테이블에서 참조할 칼럼에 제약 조건을 설정하고, 로우를 입력합니다.

 

START

    CREATE TABLE dept (
        deptno  NUMBER(2)     CONSTRAINT dept_deptno_pk PRIMARY KEY,
        dname   VARCHAR2(15),
        loc     VARCHAR2(15)
    );

    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (10, '인사', '서울');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (20, '개발', '광주');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (30, '관리', '부산');


    INSERT INTO dept02 (deptno, dname, loc)
    VALUES (40, '영업', '경기');

    COMMIT

END;

 

 

이제 자식 테이블을 만들고, 로우를 입력합니다.

 

START
    
    CREATE TABLE emp02 (
        empno   NUMBER(4)       CONSTRAINT emp02_empno_pk PRIMARY KEY,
        ename   VARCHAR2(15),
        deptno  NUMBER(2)       CONSTRAINT emp02_deptno_fk REFERENCES dept02(deptno)
    );


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (1000, 'John', 10);


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (2000, 'Smith', 20);


    INSERT INTO emp02 (empno, ename, deptno)
    VALUES (3000, 'Sam', NULL);


    -- ORA-02291: integrity constraint (SCOTT.EMP02_DEPTNO_FK) violated - parent key not found
    -- INSERT INTO emp02 (empno, ename, deptno)
    -- VALUES (4000, 'Mike', 50);

    COMMIT

END;

 

 

이제 각 테이블의 제약 조건을 데이터 사전을 통해 조회합니다.

 

SELECT
    table_name,
    constraint_type,
    constraint_name,
    r_constraint_name
FROM
    user_constraints
WHERE
    table_name IN ('DEPT02', 'EMP02')
ORDER BY
    table_name ASC;

 

FORGEIGN KEY

 

위의 결과에서, emp02 테이블의 참조키는 dept02 테이블의 기본키를 참조하는 것을 알 수 있습니다.

 

 


 

 

특정 칼럼을 참조하고 있는 자식이 있으면 해당 칼럼을 삭제할 수 없습니다.

만약 부모 테이블의 칼럼을 삭제하고 싶다면,

테이블 작성 시, FK에 ON DELETE CASCADE 키워드나 ON DELETE SET NULL 키워드를 사용하면 됩니다.

 

CREATE TABLE emp02 (
    empno NUMBER(4)     CONSTRAINT emp02_empno_pk PRIMARY KEY,
    ename VARCHAR(15),
    deptno NUMBER(2)
        CONSTRAINT emp02_deptno_fk REFERENCES dept02(deptno) ON DELETE CASCADE
);

-- ON DELETE CASCADE --
-- 참조하는 부모 테이블의 로우가 삭제되면, 해당 로우를 참조하는 자식 테이블의 로우도 연쇄 삭제됨 --



CREATE TABLE emp03 (
    empno NUMBER(4)     CONSTRAINT emp02_empno_pk PRIMARY KEY,
    ename VARCHAR(15),
    deptno NUMBER(2)
        CONSTRAINT emp03_deptno_fk REFERENCES dept02(deptno) ON DELETE SET NULL
);

-- ON DELETE SET NULL --
-- 참조하는 부모 테이블의 로우가 삭제되면, 해당 로우를 참조하는 자식 테이블의 필드값은 NULL로 바뀜--

 

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
데이터 사전  (0) 2023.08.16
크로스 조인  (0) 2023.08.10
동등 조인  (0) 2023.07.26

 

 

 

SQL은 데이터 사전을 통해 제약 조건을 확인할 수 있습니다.

 

 


 

CREATE TABLE

 

데이터 사전을 조회하기 전, 실습용 테이블을 생성하였습니다.

 

CREATE TABLE department (
    deptno NUMBER(2)    CONSTRAINT department_deptno_pk PRIMARY KEY,
    dname  VARCHAR2(15),
    loc    VARCHAR2(15)
);

-- 테이블 명만 다른 동일한 쿼리입니다. --

CREATE TABLE department2 (
    deptno NUMBER(2),
    dname  VARCHAR2(15),
    loc    VARCHAR2(15),
    
    CONSTRAINT department2_deptno_pk PRIMARY KEY (deptno)
);

 

칼럼에 제약 조건을 걸 때, 해당 로우에 제약 조건 쿼리를 작성할 수 있지만,

department2처럼 칼럼을 먼저 작성하고, 아래에 제약 조건 쿼리를 작성하여 지정할 수 있습니다.

 

 


 

 

1. USER_CONSTRAINTS

USER_CONSTRAINTS 데이터 사전은 특정 테이블의 제약 조건을 확인할 수 있지만,

어떤 칼럼에 제약 조건이 설정되어 있는지는 확인 불가합니다.

 

다음은 제약 조건의 타입입니다.

 

  • P : PRIMARY KEY (기본키)
  • R : FOREIGN KEY (외래키)
  • U : UNIQUE (고유키)
  • C : NOT NULL, CHECK ( 필드의 NULL값 제한, 칼럼에 특정 제약 조건 설정 )

 

 

다음은 department, department2 테이블의 USER_CONSTRAINTS 데이터 사전 쿼리입니다.

 

SELECT
    *
FROM
    USER_CONSTRAINTS
WHERE
    table_name IN ('DEPARTMENT', 'DEPARTMENT2');

 

USER_CONSTRAINTS

 

앞서 두 테이블의 deptno 칼럼을 PRIMARY KEY(기본키)로 제약 조건을 설정했기 때문에, 

CONSTRAINT TYPE이 P로 나왔습니다.

 

 

 

2. USER_CONS_COLUMNS

USER_CONSTRAINTS 데이터 사전은 특정 테이블의 제약 조건을 확인했다면,

USER_CONS_COLUMNS는 어떤 칼럼에 제약 조건이 설정되어 있는지 확인할 수 있습니다.

SELECT
    *
FROM
    USER_CONS_COLUMNS
WHERE
    table_name IN ('DEPARTMENT', 'DEPARTMENT2');

 

USER_CONS_COLUMNS

 

쿼리 결과처럼 deptno 칼럼이 PRIMARY KEY(기본키)로 설정되어 있음을 볼 수 있습니다.

 

 

데이터 사전을 통해 조회를 할 때, 분별력을 부여하기 위해

CREATE TABLE시, CONSTRAINT NAME을 잘 작성해야 합니다.

일반적으로 " 테이블 명_칼럼 명_키 타입" 으로 작명합니다.

 

 

 

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
크로스 조인  (0) 2023.08.10
동등 조인  (0) 2023.07.26

 

 

 

CROSS JOIN은 두 테이블의 ROW간 가능한 모든 조합을 결과로 반환하며,

이러한 CROSS JOIN의 특징을 '카티션의 곱'이라고도 합니다.

 

 


 

간단한 CROSS JOIN의 예시 코드입니다.

 

employees 테이블과 departments 테이블을 CROSS JOIN합니다.

 

SELECT
    COUNT(*)
FROM
    employees;

SELECT
    COUNT(*)
FROM
    departments;

 

먼저 각 테이블의 Row를 COUNT( * )로 조회합니다.

 

SQL

 

 

CROSS JOIN에 대한 간단한 쿼리입니다.

 

-- Oracle JOIN --

SELECT
    *
FROM
    employees,
    departments;
    

-- Ansi JOIN --

SELECT
    *
FROM
    employees CROSS JOIN departments;

 

 

 

결과는 두 테이블 Row들의 카티션의 곱즉, 107 * 27 = 2889개입니다.

 

SQL

 

만약 결과가 뜨지 않는다면 VScode의 Oracle Developer Setting에서 Max Row를 높여주시면 됩니다.

일반적으로 500개로 제한되어 있습니다.

 

 

 

 

 

 

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16
동등 조인  (0) 2023.07.26

 

 

 

EQUI JOIN은 두 개 이상의 테이블에서 같은 값이 있는 행을 합치는 방식입니다.

 

 


 

EQUI는 "equal"의 줄임말로 "같다"라는 뜻을 가지고 있습니다.

즉, EQUI JOIN은 공통의 칼럼에서 값이 "같은" 행을 결합한다는 뜻입니다.

 

다음은 EQUI JOIN에 대한 간단한 SQL 쿼리입니다.

 

-- Oracle JOIN --

SELECT
    employee_id,
    department_name
FROM
    employees t1,
    departments t2
WHERE
    t1.department_id = t2.department_id;


-- Ansi JOIN --

SELECT
    employee_id,
    department_name
FROM
    employees t1 INNER JOIN departments t2
    ON t1.department_id = t2.department_id;

 

 

 

Oracle은 두 테이블을 결합하고 WHERE절에서 체크조건으로 필터링합니다.

Ansi는 INNER JOIN으로 두 테이블을 결합하고 ON절로 필터링합니다.

 

 

저는 개인적으로 Oracle 문법이 직관적이어서 특별한 환경이 아니라면 Oracle 문법을 사용합니다.

 

 

 

'Database > SQL' 카테고리의 다른 글

그룹화  (0) 2023.08.17
인라인 뷰  (0) 2023.08.17
외래 키  (1) 2023.08.16
데이터 사전  (0) 2023.08.16
크로스 조인  (0) 2023.08.10

+ Recent posts