💽 DataBase
SQL 데이터 조회
SELECT로 데이터 조회
Select Statement
- ID가 9인 임직원의 이름과 직군을 알고 싶다.
Projection Attributes
관심있는 Attributes
- 교차가 되는 두 값만 가져옴
정리
Select Statement
- Project 2002를 리딩하는 임직원의 ID와 이름, 직군을 찾자
AS
Table이나 Attribute에 별칭(Alias)을 붙일 때 사용
- 생략 가능
생략
DISTINCT
Select 결과에서 중복되는 Tuple들을 제외하고 싶을 때 사용
Distinct Statement
- 디자이너들이 참여하고 있는 프로젝트들의 ID와 이름을 알고 싶다.
중복 제거
LIKE
Like Statement
- 이름이 N으로 시작하거나, N으로 끝나는 임직원들의 이름을 알고 싶다.
Like Statement
- 이름에 NG가 들어가는 임직원들의 이름을 알고 싶다.
Like Statement
- 이름이 J로 시작하는, 총 4 글자의 이름을 가지는 임직원들의 이름
Escape 문자와 함께
- %로 시작하거나 _로 끝나는 프로젝트 이름을 찾고 싶을 때
정리
* (asterisk)
선택된 Tuple들의 모든 Attribute들을 보여주고 싶을 때 사용
- ID가 9인 임직원의 모든 Attribute들을 알고 싶다.
SELECT without WHERE
Table에 있는 모든 Tuple들을 반환
Statement
- 모든 임직원의 이름과 생일을 알고 싶다.
주의사항
- SELECT로 조회할 때 조건들을 포함해서 조회하면, 이 조건들과 관련된 Attributes에 Index가 걸려있어야 한다.
- 그렇지 않으면, 데이터가 많아질수록 조회 속도가 느려진다.
- 이 자료는 MySQL 기준
Subquery
SELECT with subquery
- ID가 14인 임직원보다 생일이 빠른 임직원의 ID, 이름, 생일을 알고 싶다.
- 두번의 쿼리로 나누어 실행된 쿼리를 하나의 쿼리로
subquery(nested query or inner query)
SELECT, INSERT, UPDATE, DELETE에 포함된 query
- subquery는 () 안에 기술된다.
outer query(main query)
subquery를 포함하는 query
Statement
- ID가 1인 임직원과 같은 부서, 같은 성별인 임직원들의 ID와 이름, 직군을 알고 싶다.
- ID가 5인 임직원과 같은 프로젝트에 참여한 임직원들의 ID를 알고 싶다.
IN
- Unqualified Attribute가 참조하는 Table은 해당 Attribute가 사용된 query를 포함하여 그 query 바깥쪽으로 존재하는 모든 query들 중에 해당 Attribute 이름을 가지는 가장 가까이에 있는 Table을 참조
Statement
- ID가 5인 임직원과 같은 프로젝트에 참여한 임직원들의 ID와 이름을 알고 싶다.
From에 subquery
EXISTS
Statement
- ID가 7 or 12인 임직원이 참여한 프로젝트의 ID와 이름을 알고 싶다.
정리
- Correlated Query: subquery가 바깥쪽 query의 Attribute를 참조할 때, Correlated Subquery라 부름
- EXISTS: subquery의 결과가 최소 하나의 row라도 있다면 TRUE를 반환
- NOT EXISTS: subquery의 결과가 단 하나의 row라도 없다면 TRUE를 반환
IN으로 바꿀 수 있음
Statement
- 2000년대생이 없는 부서의 ID와 이름을 알고 싶다.
IN으로 바꿈
ANY
Statement
- 리더보다 높은 연봉을 받는 부서원을 가진 리더의 ID와 이름, 연봉을 알고 싶다.
정리
- v comparison_operator ANY (subquery): subquery가 반환한 결과들 중에 단 하나라도 v와의 비교 연산이 TRUE라면, TRUE 반환
- SOME도 ANY와 같은 역할을 한다.
Statement
- 리더보다 높은 연봉을 받는 부서원을 가진 리더의 ID와 이름, 연봉, 해당 부서 최고 연봉을 알고 싶다.
SELECT 절에도 subquery 들어갈 수 있음
ALL
Statement
- ID가 13인 임직원과 한번도 같은 프로젝트에서 참여하지 못한 임직원들이 ID, 이름, 직군을 알고 싶다.
정리
- v comparison_operator ALL (subquery): subquery가 반환된 결과들과 v와의 비교 연산이 모두 TRUE라면, TRUE 반환
참고사항
- 성능 비교: IN vs EXISTS
- 최근에는 거의 차이 없음
- MySQL 기준
NULL
- Unknown
- Unavailable or withheld
- not applicable
SQL에서 NULL의 의미
- id 14, 15의 생일이 같은 NULL이라고 하면, 생일이 같은 것인가?
- 생일이 NULL인 것이 없는게 아니다!
IS
NULL과 Three-Valued Logic
- 여기서 이 명령을 실행하면 FALSE가 나올 것이라 예상하지만
- 결과는 UNKNOWN
- TRUE 일 수도 있고, FALSE 일 수도 있다라는 의미
- Three-Valued Logic: 비교/논리 연산의 결과로 TRUE, FALSE, UNKNOWN을 가진다.
WHERE 절의 Conditions
WHERE 절에 있는 condition의 결과가 TRUE인 Tuple들만 선택된다.
- 결과가 FALSE거나 UNKNOWN이면 Tuple은 선택되지 않는다.
NOT IN 사용 시 주의 사항
v NOT IN(v1, v2, v3)
v != v1 AND v != v2 AND v != v3
- 만약 v1, v2, v3 중 하나가 NULL 이라면?
UNKNOWN 해결 방안
NOT NULL Constraint
IS NOT NULL 사용
NOT EXISTS 사용
JOIN
두 개 이상의 Table들에 있는 데이터를 한 번에 조회하는 것
- 여러 종류의 JOIN이 존재
Statement
- ID가 1인 임직원이 속한 부서의 이름?
Implicit JOIN
FROM 절에는 Table들만 나열, WHERE 절에 JOIN Condition을 명시
- Old-Style JOIN Syntax
- WHERE 절에 Selection Condition과 JOIN Condition이 같이 있기 때문에 가독성이 떨어짐
- 복잡한 JOIN 쿼리를 작성하다 보면 잘못된 쿼리를 작성할 가능성이 크다.
Explicit JOIN
FROM 절에 JOIN 키워드와 함께 Joined Table들을 명시하는 방식
- FROM 절에서 ON 뒤에 Join Condition이 명시됨
- 가독성이 좋음
- 복잡한 JOIN 쿼리 작성 중에도 실수할 가능성이 적다.
INNER JOIN
두 Table 사이에서 JOIN Condition을 만족하는 Tuple들로만 Result Table을 만드는 JOIN
- JOIN 키워드 앞에 INNER가 생략되어있는 것
- FROM table1 [INNER] JOIN table2 ON join_condition
- Join Condition에 사용 가능한 연산자(Operator): =, <, >, ≠ 등 여러 비교 연산자 가능
- Join Condition에서 NULL값을 가지는 Tuple은 Result Table에 포함되지 못한다.
OUTER JOIN
두 Table에서 Join Condition을 만족하지 않는 Tuple들도 Result Table에 포함하는 JOIN
- FROM table1 LEFT [OUTER] JOIN table2 ON join_condition
- FROM table1 RIGHT [OUTER] JOIN table2 ON join_condition
- FROM table1 FULL [OUTER] JOIN table2 ON join_condition
- Join Condition에 사용 가능한 연산자(Operator): =, <, >, ≠ 등 여러 비교 연산자 가능
LEFT OUTER JOIN
RIGHT OUTER JOIN
FULL OUTER JOIN
MySQL에서는 지원하지 않음
EQUI JOIN
Join Condition에서 = (Equality Comparator)를 사용하는 JOIN
- INNER JOIN, OUTER JOIN 상관 없이 = 를 사용한 JOIN이라면 EQUI JOIN으로 보는 경우
- INNER JOIN으로 한정해서 = 를 사용한 JOIN만 EQUI JOIN으로 보는 경우
USING
두 Table이 EQUI JOIN 할 때 JOIN하는 Attribute의 이름이 같다면, USING으로 간단하게 작성
- 이 때, 같은 이름의 Attribute는 Result Table에서 한번만 표시됨
- FROM table1 [INNER] JOIN table2 USING (attributes)
- FROM table1 LEFT [OUTER] JOIN table2 USING (attributes)
- FROM table1 RIGHT [OUTER] JOIN table2 USING (attributes)
- FROM table1 FULL [OUTER] JOIN table2 USING (attributes)
NATURAL JOIN
두 Table에서 같은 이름을 가지는 모든 Attribute Pair에 대해서 EQUI JOIN을 수행
- Join Condition을 따로 명시하지 않는다.
- 사용 불가
- FROM table1 NATURAL [INNER] JOIN table2
- FROM table1 NATURAL LEFT [OUTER] JOIN table2
- FROM table1 NATURAL RIGHT [OUTER] JOIN table2
- FROM table1 NATURAL RULL [OUTER] JOIN table2
이번에는 Attribute 이름을 바꿈
- 같은 이름의 Attribute가 두 쌍이 있음
- 이 쿼리들과 같으므로, 결과는 Empty set
CROSS JOIN
두 Table의 Tuple Pair로 만들 수 있는 모든 조합(Cartesian Product)을 Result Table로 반환
- Join Condition 사용 가능
- Implicit CROSS JOIN: FROM table1, table2
- Explicit CROSS JOIN: FROM table1 CROSS JOIN table2
CROSS JOIN @ MySQL
- 표준과 약간 다름
- MySQL은 CROSS JOIN == INNER JOIN == JOIN
- CROSS JOIN에 ON(or USING)을 같이 쓰면, INNER JOIN으로 동작
- INNER JOIN(or JOIN을 ON(or USING) 없이 사용하면, CROSS JOIN으로 동작
SELF JOIN
Table이 자기 자신에게 JOIN 하는 경우
JOIN을 사용한 예제
JOIN Example
- ID가 1003인 부서에 속하는 임직원 중 리더를 제외한 부서원의 ID, 이름, 연봉을 알고 싶다.
- ID가 2001인 프로젝트에 참여한 임직원들의 이름과 직군, 소속 부서 이름을 알고 싶다.
ORDER BY
조회 결과를 특정 Attribute 기준으로 정렬하여 가져오고 싶을 때 사용
- Default 정렬 방식은 오름차순(ASC)
- 오름차순 == ASC
- 내림차순 == DESC
ORDER BY Example
- 임직원들의 정보를 연봉 순서대로 정렬해서 알고 싶다.
Aggregate Function
여러 Tuple들의 정보를 요약해서 하나의 값으로 추출하는 함수
- 대표적으로 COUNT, SUM, MAX, MIN, AVG 함수가 있음
- 관심있는 Attribute에 사용된다. ex) AVG(salary), MAX(birth_date)
- NULL 값들은 제외하고 요약 값을 추출한다.
Aggregate Function Example
- 임직원 수를 알고 싶다.
position으로 바꿔도 같은 결과
- == 중복을 제거하지 않고 개수를 센다는 뜻
dept_id로 바꾸면
- NULL을 제외하고 개수를 센다.
따라서 Tuple의 개수를 얻고 싶다면 *를 써라.
Aggregate Function Example
- 프로젝트 2002에 참여한 임직원 수와 최대 연봉, 최소 연봉, 평균 연봉을 알고 싶다.
GROUP BY
관심있는 Attribute 기준으로 그룹을 나눠서, 그룹별로 Aggregate Function을 적용하고 싶을 때 사용
- Grouping Attribute(s): 그룹을 나누는 기준이 되는 Attribute
- Grouping Attribute(s)에 NULL 값이 있을 때, NULL 값을 가지는 Tuple들끼리 묶인다.
GROUP BY Example
HAVING
Aggregate Function의 결과값을 바탕으로 그룹을 필터링하고 싶을 때 사용
- GROUP BY와 함께 사용
- HAVING 절에 명시된 조건을 만족하는 그룹만 결과에 포함됨
HAVING Example
- 프로젝트 참여 인원이 7명 이상인 프로젝트들에 대해서 각 프로젝트에 참여한 임직원 수와 최대 연봉, 최소 연봉, 평균 연봉을 알고 싶다.
HAVING Example
- 각 부서별 인원 수를 인원 수가 많은 순서대로 정렬해서 알고 싶다.
- 각 부서별 - 성별 인원 수를 인원 수가 많은 순서대로 정렬해서 알고 싶다.
HAVING Example
- 회사 전체 평균 연봉보다 평균 연봉이 적은 부서들의 평균 연봉을 알고 싶다.
HAVING Example
- 각 프로젝트 별로 프로젝트에 참여한 90년대생들의 수와 이들의 평균 연봉을 알고 싶다.
- 각 프로젝트 별로 참여 인원이 7명 이상인 프로젝트에 참여한 90년대생들의 수와 이들의 평균 연봉을 알고 싶다.
정리
SELECT attribute(s) or aggregate function(s)
FROM table(s)
[ WHERE condition(s) ]
[ GROUP BY group attribute(s) ]
[ HAVING group condition(s) ]
[ ORDER BY attribute(s) ]
개념적인 실행 순서
- SELECT attribute(s) or aggregate function(s)
- FROM table(s)
- [ WHERE condition(s) ]
- [ GROUP BY group attribute(s) ]
- [ HAVING group condition(s) ]
- [ ORDER BY attribute(s) ]
실제 실행 순서
각 RDBMS에서 어떻게 구현했는지에 따라 다르다.