데이터베이스 두 가지 이상의 테이블 합치는 방법
서브쿼리와 조인
데이터베이스에서 두 가지 이상의 테이블을 함께 사용하는 방법으로 서브쿼리(Subquery)와 조인(join)이라는 방법이 있다. 서브쿼리는 쿼리 안에 또 다른 쿼리를 넣은 것이고, 조인은 데이터베이스에서 제공하는 행을 합해주는 연산자다. 두 가지 방법 중 어떤 방법이 더 좋은지는 작성할 쿼리문에 따라 다르기 때문에 판단을 내릴 수 없다.
서브쿼리(Subquery)
샘플 데이터
<사용자 테이블>
id | username | password | |
1 | ssar | 1234 | ssar@nate.com |
2 | sai | 1234 | sai@naver.com |
<게시글 테이블>
id | title | content | userId |
1 | 제목1 | 내용1 | 1 |
2 | 제목2 | 내용2 | 2 |
3 | 제목3 | 내용3 | 2 |
<댓글 테이블>
id | content | userId | boarId |
1 | 댓글1 | 1 | 1 |
2 | 댓글2 | 1 | 2 |
3 | 댓글3 | 1 | 2 |
4 | 댓글4 | 3 | 1 |
1.서브쿼리
서브쿼리는 WHERE 절에 있는 보조 쿼리를 말한다.
서브쿼리 예제
댓글이 달린 게시글을 모두 출력하라.
SELECT * FROM board
WHERE id IN (SELECT distinct boardId FROM comment);
SELECT distinct boardId FROM comment
댓글이 달린 게시글 번호를 중복 제거하여 찾아낸다.
SELECT * FROM board WHERE id IN (서브쿼리);
게시글 번호가 서브쿼리인 게시글의 모든 칼럼을 출력한다.
결과
id | title | content | userId |
1 | 제목1 | 내용1 | 1 |
3 | 제목3 | 내용3 | 2 |
스칼라 서브쿼리 응용
SELECT
id,
title,
content,
(SELECT usernamea from user WHERE id = userId)
FROM board
WHERE id IN (SELECT distinct boardId FROM comment);
결과
id | title | content | (SELECT usernamea from user WHERE id = userId) |
1 | 제목1 | 내용1 | ssar |
3 | 제목3 | 내용3 | sai |
셀렉트문이 적으면 가독성이 좋지만 만약 셀렉트문이 많아지면 행마다 연산이 일어나기 때문에 스칼라 서브쿼리를 사용하기 적절하지 않다. 이런 경우 조인을 사용하면 연산을 간결하게 할 수 있다.
인라인 서브쿼리(인라인 뷰)
FROM 절에 있는 보조쿼리. 인라인 서브쿼리는 메모리에 있는 데이터를 다시 가지고 온다.
SELECT *
FROM
(
SELECT id, content
FROM board
) b;
SELECT id, content FROM board
하드디스크에 있는 데이터를 가지고 온다.
SELECT * FROM ( SELECT id, content FROM board ) b;
이미 메모리에 있던 데이터를 다시 가지고 온다.
인라인 서브쿼리를 사용하는 이유
오라클에서는 RANK 함수 사용하여 아주 간단하게 구할 수 있어요.
오라클에서는 RANK 함수 사용하여 아주 간단하게 구할 수 있어요.
SELECT
first_name, salary
RANK() OVER (ORDER BY salary DESC)
FROM employees
\오라클 외의 데이터베이스에서는 RANK 함수가 별도로 제공되지 않습니다. 하지만 ROWNUM과 인라인 서브쿼리를 활용하면 순위를 구할 수 있어요.
\오라클 외의 데이터베이스에서는 RANK 함수가 별도로 제공되지 않습니다. 하지만 ROWNUM과 인라인 서브쿼리를 활용하면 순위를 구할 수 있어요.
SELECT first_name, salary
ROWNUM
FROM
(
-- 인라인 서브쿼리
SELECT first_name, salary
FROM employees
ORDER BY 2 Desc
);
ROWNUM은 데이터를 가지고 오는 순서대로 번호를 매기는 함수입니다. 그래서 salary로 정렬해도 의미가 없어지는데요. 여기서 인라인 서브쿼리를 사용하면 이미 순서대로 메모리에 올라가 있는 데이터에서 데이터를 가지고 올 수 있기 때문에 이 때 ROWNUM을 사용하여 순서대로 번호를 매길 수 있게 됩니다.
ROWNUM은 데이터를 가지고 오는 순서대로 번호를 매기는 함수입니다. 그래서 salary로 정렬해도 의미가 없어지는데요. 여기서 인라인 서브쿼리를 사용하면 이미 순서대로 메모리에 올라가 있는 데이터에서 데이터를 가지고 올 수 있기 때문에 이 때 ROWNUM을 사용하여 순서대로 번호를 매길 수 있게 됩니다.
SELECT
first_name, salary, ROWNUM
FROM employees
ORDER BY 2 Desc;
인라인 서브쿼리 없이 ROWNUM만 사용할 경우
3.스칼라 서브쿼리
SELECT 절에 있는 보조쿼리를 말한다.
스칼라 서브쿼리 예제
가장 최신글 번호를 각 게시글과 함께 출력하세요.
SELECT id, content, (SELECT MAX(id) FROM board) FROM board;
총 게시글 수와 게시글을 함께 출력하세요.
SELECT id, content, (SELECT COUNT(id) FROM board) FROM board;
게시글과 사용자 이름을 함께 출력하세요.
SELECT id, content, userId,
(SELECT username FROM user WHERE id = userId)
FROM board;
조인(Join)
드라이빙 테이블
드라이빙 테이블(DT) 공식
N(DT) : 1
드라이빙 테이블이 게시글 테이블인 경우
드라이빙 테이블이 댓글 테이블인 경우
Innter Join
이너조인 예제
댓글이 달린 게시글을 모두 출력하라.
1
SELECT * FROM comment c INNER JOIN board b,
ON c.boardId = b.id;
2
SELECT
b.id ‘게시글번호’,
bi.title ‘게시글제목’,
b.content ‘게시글내용’,
c.content ‘댓글내용’,
b.userId ’게시글작성자’,
c.userId ‘댓글작성자’
FROM comment c INNER JOIN board b
ON c.boardId = b.id;
Outer Join
Left Outer Join
SELECT
*
FROM board b left JOIN comment c
ON c.boardId = b.id;
Right Outer Join
SELECT
*
FROM comment c right OUTER JOIN board b
ON c.boardId = b.id;