SQL (3)
6. JOIN
조인이란?
- 다수의 table간에 공통된 데이터를 기준으로 검색하는 명령어
- 다수의 table 이란?
- 동일한 table을 논리적으로 다수의 table로 간주: self join
- 물리적으로 다른 table간의 조인
table에 별칭 사용
- 검색시 다중 table의 컬럼명이 다를 경우 table별칭 사용 불필요,
- 서로 다른 table간의 컬럼명이 중복된 경우, 컬럼 구분을 위해 오라클 엔진에게 정확한 table 소속명을 알려줘야 함
- 주의사항 : table별칭 as 사용 불가
종류
- EQUI JOIN: 공통 필드의 레코드를 가져오는 방법 (중복)
- INNER JOIN (중복 제거)- OUTER JOIN: INNER JOIN 확장 (INNER JOIN + 공통되지 않은 레코드도 가져옴)
- LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN- NON-EQUI JOIN: 공통되지 않는 필드의 레코드를 가져오는 방법
- SELF JOIN
SET 연산자:
- UNION, UNION ALL, INTERSECT, EXCEPT
INNER JOIN
테이블에서 같은 조건이 존재할 경우의 값 검색
SELECT tableA.id, tableA.value
FROM tableA INNER JOIN tableB
ON tableA.id = tableB.id;
-- 별명 주기!
-- note: 별명주면 별명만 사용해야 함, table 별명 as 사용 불가
SELECT a.id, a.value
FROM tableA a INNER JOIN tableB b
ON a.id = b.id;
-- mysql 자체 문법
SELECT a.id, a.value
FROM tableA a, tableB b
WHERE a.id = b.id;
-- 직원의 사번, 이름, 업무, 부서번호, 부서명을 조회
SELECT empno, ename, job, scott_emp.deptno, dname
FROM scott_emp INNER JOIN scott_dept
ON scott_emp.deptno = scott_dept.deptno;
+-------+--------+-----------+--------+------------+
| empno | ename | job | deptno | dname |
+-------+--------+-----------+--------+------------+
| 7782 | CLARK | MANAGER | 10 | ACCOUNTING |
| 7839 | KING | PRESIDENT | 10 | ACCOUNTING |
| 7934 | MILLER | CLERK | 10 | ACCOUNTING |
| 7369 | SMITH | CLERK | 20 | RESEARCH |
| 7566 | JONES | MANAGER | 20 | RESEARCH |
| 7788 | SCOTT | ANALYST | 20 | RESEARCH |
| 7876 | ADAMS | CLERK | 20 | RESEARCH |
| 7902 | FORD | ANALYST | 20 | RESEARCH |
| 7499 | ALLEN | SALESMAN | 30 | SALES |
| 7521 | WARD | SALESMAN | 30 | SALES |
| 7654 | MARTIN | SALESMAN | 30 | SALES |
| 7698 | BLAKE | MANAGER | 30 | SALES |
| 7844 | TURNER | SALESMAN | 30 | SALES |
| 7900 | JAMES | CLERK | 30 | SALES |
+-------+--------+-----------+--------+------------+
-- salesman에 대해서 직원의 사번, 이름, 업무, 부서번호, 부서명을 조회
-- ! 조건을 조인하면서 같이줄 때
SELECT empno, ename, job, e.deptno, dname
FROM scott_emp e INNER JOIN scott_dept d
ON e.deptno = d.deptno AND job = 'salesman';
-- ! 조건을 조인 하고 나서 뒤에 줄 때
SELECT empno, ename, job, e.deptno, dname
FROM scott_emp e INNER JOIN scott_dept d
ON e.deptno = d.deptno
WHERE job = 'salesman';
+-------+--------+----------+--------+-------+
| empno | ename | job | deptno | dname |
+-------+--------+----------+--------+-------+
| 7499 | ALLEN | SALESMAN | 30 | SALES |
| 7521 | WARD | SALESMAN | 30 | SALES |
| 7654 | MARTIN | SALESMAN | 30 | SALES |
| 7844 | TURNER | SALESMAN | 30 | SALES |
+-------+--------+----------+--------+-------+
-- New york에서 근무하는 직원의 이름, 업무, 부서명 조회
SELECT ename, job, scott_dept.dname
FROM scott_dept INNER JOIN scott_emp
ON scott_emp.deptno = scott_dept.deptno
WHERE loc = 'NEW YORK';
+--------+-----------+------------+
| ename | job | dname |
+--------+-----------+------------+
| CLARK | MANAGER | ACCOUNTING |
| KING | PRESIDENT | ACCOUNTING |
| MILLER | CLERK | ACCOUNTING |
+--------+-----------+------------+
OUTER JOIN
두개 이상의 테이블이 조인될때 특정 데이터가 모든 테이블에 존재하지 않고 컬럼은 존재하나 null값을 보유한 경우 검색되지 않는 문제를 해결하기 위해 사용되는 조인
SELECT a.id, a.value
FROM tableA a LEFT OUTER JOIN tableB b
ON a.id = b.id;
+------+-------+
| id | value |
+------+-------+
| 1 | 10 |
| 2 | 20 |
| 5 | 50 |
| 3 | 30 |
| 7 | 70 |
+------+-------+
SELECT b.id, b.value
FROM tableA a RIGHT OUTER JOIN tableB b
ON a.id = b.id;
+------+-------+
| id | value |
+------+-------+
| 1 | 10 |
| 2 | 20 |
| 5 | 50 |
| 4 | 40 |
| 8 | 80 |
+------+-------+
-- 직원들의 이름, 급여, 근무지를 조회. 단, 부서명과 근무지는 모두 출력할 수 있도록 하시오
SELECT ename, sal, dname, loc
FROM scott_emp RIGHT OUTER JOIN scott_dept
ON scott_emp.deptno = scott_dept.deptno;
+--------+------+------------+----------+
| ename | sal | dname | loc |
+--------+------+------------+----------+
| CLARK | 2450 | ACCOUNTING | NEW YORK |
| KING | 5000 | ACCOUNTING | NEW YORK |
| MILLER | 1300 | ACCOUNTING | NEW YORK |
| SMITH | 800 | RESEARCH | DALLAS |
| JONES | 2975 | RESEARCH | DALLAS |
| SCOTT | 3000 | RESEARCH | DALLAS |
| ADAMS | 1100 | RESEARCH | DALLAS |
| FORD | 3000 | RESEARCH | DALLAS |
| ALLEN | 1600 | SALES | CHICAGO |
| WARD | 1250 | SALES | CHICAGO |
| MARTIN | 1250 | SALES | CHICAGO |
| BLAKE | 2850 | SALES | CHICAGO |
| TURNER | 1500 | SALES | CHICAGO |
| JAMES | 950 | SALES | CHICAGO |
| NULL | NULL | OPERATIONS | BOSTON |
+--------+------+------------+----------+
NON-EQUI JOIN
100% 일치하지 않고 특정 범위내의 데이터 조인시에 사용
---직원들의 사번, 이름, 급여, 급여등급 조회
SELECT empno, ename, sal, grade, losal, hisal
FROM scott_emp e INNER JOIN scott_salgrade s
ON e.sal >= s.losal AND e.sal <= s.hisal;
+-------+--------+------+-------+-------+-------+
| empno | ename | sal | grade | losal | hisal |
+-------+--------+------+-------+-------+-------+
| 7369 | SMITH | 800 | 1 | 700 | 1200 |
| 7499 | ALLEN | 1600 | 3 | 1401 | 2000 |
| 7521 | WARD | 1250 | 2 | 1201 | 1400 |
| 7566 | JONES | 2975 | 4 | 2001 | 3000 |
| 7654 | MARTIN | 1250 | 2 | 1201 | 1400 |
| 7698 | BLAKE | 2850 | 4 | 2001 | 3000 |
| 7782 | CLARK | 2450 | 4 | 2001 | 3000 |
| 7788 | SCOTT | 3000 | 4 | 2001 | 3000 |
| 7839 | KING | 5000 | 5 | 3001 | 9999 |
| 7844 | TURNER | 1500 | 3 | 1401 | 2000 |
| 7876 | ADAMS | 1100 | 1 | 700 | 1200 |
| 7900 | JAMES | 950 | 1 | 700 | 1200 |
| 7902 | FORD | 3000 | 4 | 2001 | 3000 |
| 7934 | MILLER | 1300 | 2 | 1201 | 1400 |
+-------+--------+------+-------+-------+-------+
SELF JOIN
동일 테이블 내에서 상이한 칼럼 참조
-- 직원의 사번, 이름, 업무, 관리자, 관리자이름 조회
-- 별명주기 필수
SELECT e.empno, e.ename, e.job, e.mgr, m.ename
FROM scott_emp e INNER JOIN scott_emp m
ON e.mgr = m.empno;
+-------+--------+----------+------+-------+
| empno | ename | job | mgr | ename |
+-------+--------+----------+------+-------+
| 7369 | SMITH | CLERK | 7902 | FORD |
| 7499 | ALLEN | SALESMAN | 7698 | BLAKE |
| 7521 | WARD | SALESMAN | 7698 | BLAKE |
| 7566 | JONES | MANAGER | 7839 | KING |
| 7654 | MARTIN | SALESMAN | 7698 | BLAKE |
| 7698 | BLAKE | MANAGER | 7839 | KING |
| 7782 | CLARK | MANAGER | 7839 | KING |
| 7788 | SCOTT | ANALYST | 7566 | JONES |
| 7844 | TURNER | SALESMAN | 7698 | BLAKE |
| 7876 | ADAMS | CLERK | 7788 | SCOTT |
| 7900 | JAMES | CLERK | 7698 | BLAKE |
| 7902 | FORD | ANALYST | 7566 | JONES |
| 7934 | MILLER | CLERK | 7782 | CLARK |
+-------+--------+----------+------+-------+
세개 이상 JOIN
SELECT a.id, a.value, b.id, b.value, c.id, c.value
FROM tableA a INNER JOIN tableB b
ON a.id = b.id
INNER JOIN tableC c
ON b.id = c.id;
-- mysql 자체 문법
SELECT a.id, a.value, b.id, b.value, c.id, c.value
FROM tableA a, tableB b, tableC c
WHERE a.id = b.id AND b.id = c.id;
SET 연산자
SELECT deptno FROM scott_emp
UNION
SELECT deptno FROM scott_dept;
+--------+
| deptno |
+--------+
| 10 |
| 20 |
| 30 |
| 40 |
+--------+
SELECT deptno FROM scott_emp
UNION ALL
SELECT deptno FROM scott_dept;
+--------+
| deptno |
+--------+
| 10 |
| 10 |
| 10 |
| 20 |
| 20 |
| 20 |
| 20 |
| 20 |
| 30 |
| 30 |
| 30 |
| 30 |
| 30 |
| 30 |
| 10 |
| 20 |
| 30 |
| 40 |
+--------+
7. 데이터 무결성 (Integrity)
제약: Constraint What? How?
- 실체 (Entity: 주로 table을 의미) 무결성
- 데이터 중복 방지
- PRIMARY KEY, UNIQUE- 영역 (Domain) 무결성
- CHECK (mysql은 x)- 참조 (Reference) 무결성
- FOREIGN KEY
- 부모: 참조 당하는 table, 자식: 참조하는 table
컬럼의 속성
- NN (Not Null)
- PRIMARY KEY- ND (Not Duplicate)
- PRIMARY KEY
- UNIQUE- NC (Not Change)
- FOREIGN KEY
PRIMARY KEY (NN & ND)
CREATE TABLE tableEXAM(
id int,
name varchar(10)
);
INSERT INTO tableEXAM(id) VALUES(1);
INSERT INTO tableEXAM(id) VALUES(1);
-- PRIMARY KEY: 한 테이블 당 한개만 소유
ALTER TABLE tableEXAM ADD CONSTRAINT pk_id PRIMARY KEY(id);
DELETE FROM tableEXAM;
ALTER TABLE tableEXAM ADD CONSTRAINT pk_id PRIMARY KEY(id);
-- ND
INSERT INTO tableEXAM(id) VALUES(1);
INSERT INTO tableEXAM(id) VALUES(1); -- ERROR
-- NN
INSERT INTO tableEXAM(name) VALUES('kimmy'); -- ERROR
-- PRIMARY KEY 지정 방법
DROP TABLE tableEXAM;
--하나의 field에만 primary key
CREATE TABLE tableEXAM(
id int PRIMARY KEY,
name varchar(10)
);
DROP TABLE tableEXAM;
-- 여러 field를 하나의 primary key로 가능 (권장)
CREATE TABLE tableEXAM(
id int,
name varchar(10),
CONSTRAINT pk_id PRIMARY KEY(id)
);
-- NN
CREATE TABLE tableEXAM(
id int not null,
name varchar(10) not null
);
-- name을 null 로
ALTER TABLE tableEXAM MODIFY name varchar(10) null;
ALTER TABLE tableEXAM ADD age int null;
UNIQUE (ND)
-- UNIQUE: ND 속성을 지켜줌
DROP TABLE tableEXAM;
CREATE TABLE tableEXAM(
id int,
name varchar(10),
age int
);
ALTER TABLE tableEXAM ADD CONSTRAINT uk_id UNIQUE(id);
ALTER TABLE tableEXAM ADD CONSTRAINT uk_name UNIQUE(name);
INSERT INTO tableEXAM(id, name, age) VALUES(1, 'kimmy', 20);
-- ND
INSERT INTO tableEXAM(id, name, age) VALUES(1, 'lee', 20);
--> ERROR: Duplicate entry '1' for key 'uk_id'
INSERT INTO tableEXAM(id, name, age) VALUES(2, 'kimmy', 20);
--> ERROR: Duplicate entry 'kimmy' for key 'uk_name'
-- NN 속성은 방지 x
INSERT INTO tableEXAM(id, name, age) VALUES(null, 'jimmy', 20);
--> Query OK, 1 row affected
-- null값 중복은 ok
INSERT INTO tableEXAM(id, name, age) VALUES(null, 'elsa', 20);
--> Query OK, 1 row affected
/* NN & ND 선처리 방식 (제약 조건은 x)
NN: DEFAULT
ND: AUTO_INCREMENT
*/
DROP TABLE tableEXAM;
CREATE TABLE tableEXAM(
id int AUTO_INCREMENT,
name varchar(10) DEFAULT 'no name',
age int DEFAULT 20,
CONSTRAINT uk_id UNIQUE(id)
);
INSERT INTO tableEXAM(name, age) VALUES ('scott', 20);
INSERT INTO tableEXAM(age) VALUES (30);
INSERT INTO tableEXAM(name) VALUES ('miller');
FOREIGN KEY (NC)
CREATE TABLE tableDEPT(
deptno int,
dname varchar(10)
);
INSERT INTO tableDEPT VALUES(100, 'SALES');
INSERT INTO tableDEPT VALUES(101, 'MARKETING');
INSERT INTO tableDEPT VALUES(102, 'RESEARCH');
CREATE TABLE tableEMP(
empno int,
ename varchar(20),
hiredate datetime,
deptno int
);
-- deptno에 제약이 없으면 참조키를 달 수 없음
ALTER TABLE tableDEPT ADD CONSTRAINT pk_deptno PRIMARY KEY(deptno);
ALTER TABLE tableEMP
ADD CONSTRAINT fk_deptno FOREIGN KEY(deptno)
REFERENCES tableDEPT(deptno);
INSERT INTO tableEMP(empno, ename, hiredate, deptno) VALUES(1, 'scott', now(), 103);
--> ERROR: Cannot add or update a child row: a foreign key constraint fails
INSERT INTO tableEMP(empno, ename, hiredate, deptno) VALUES(1, 'scott', now(), 102);
--> Query OK, 1 row affected
-- NC
UPDATE tableDEPT SET deptno = 1002 WHERE deptno = 102;
--> ERROR: Cannot delete or update a parent row: a foreign key constraint fails
-- NC (삭제 x)
DROP TABLE tableDEPT;
--> ERROR: Cannot delete or update a parent row: a foreign key constraint fails
Example
| column name | post1 | post2 | addr |
|---|---|---|---|
| key type | PK | PK | |
| nulls/unique | NN | ||
| max length | 3 | 3 | 60 |
| sample | seoul, south korea |
| column name | id | name | sex | jumin1 | jumin2 | tel | post1 | post2 | addr |
|---|---|---|---|---|---|---|---|---|---|
| key type | PK | FK | FK | ||||||
| nulls/unique | NN | UK | UK | ||||||
| FK ref table | POST | ||||||||
| FK ref column | post1 | post2 | |||||||
| data type | INT | VARCHAR | CHAR | CHAR | CHAR | VARCHAR | CHAR | CHAR | VARCHAR |
| max length | 4 | 10 | 1 | 6 | 7 | 15 | 3 | 3 | 60 |
| sample | 1234 | hgd | 1 | 990101 | 1232344 | 712-1234 | 100 | 010 |
CREATE TABLE POST(
post1 char(3),
post2 char(3),
addr varchar(60) DEFAULT 'no addr',
CONSTRAINT pk_post PRIMARY KEY(post1, post2)
);
CREATE TABLE MEMBER(
id int(4) PRIMARY KEY,
name varchar(10) DEFAULT 'kimmy',
sex char(1),
jumin1 char(6),
jumin2 char(7),
tel varchar(15),
post1 char(3),
post2 char(3),
addr varchar(60)
);
ALTER TABLE MEMBER ADD CONSTRAINT uk_jumin UNIQUE(jumin1, jumin2);
ALTER TABLE MEMBER ADD CONSTRAINT fk_post FOREIGN KEY(post1, post2) REFERENCES POST(post1, post2);