Relational Languages
- Data Manipulatin Language (DML) :
SELECT,INSERT,UPDATE,DELETE - Data Definition Language (DDL)
- Data Control Language (DCL) : 보안, 권한 제어 등
sets(unordered, no duplicates)에 기반한 Relational algebra와 달리, SQL은 bags(unordered, allows duplicates)에 기반
=> 중복 허용
Aggregates
-
Functions that return a single value from a bag of tuples.
-
e.g.
AVG(col),MIN(col),MAX(col),SUM(col),COUNT(col) -
SELECT아웃풋 문의 Non-aggregated 값 필드는GROUP BYclause에 나와야 함.
잘못된 쿼리 :
SELECT AVG(s.gpa), e.cid
FROM enrolled AS e JOIN student AS s
ON e.sid = s.sid
String Operations
- SQL 표준은 case sensitive, single-quotes only.
- cf) MySQL 기본 모드는 cass insensitive
- Pattern Matching
LIKE키워드는 조건식에서 문자열을 매칭할 때 사용된다.- ”%”는 (공백을 포함한) 임의의 substring
- “_“는 임의의 문자 한 개.
- SQL-92에 여러 string 함수가 있고, 여러 DB 시스템은 표준 함수와 각자의 함수를 구현해둠
- Concatenation: “||“는 문자열을 이어줌.
Output Redirection
- 새 테이블 : 쿼리 결과를 새 테이블에 저장
SELECT DISTINCT cid INTO CourseIds FROM enrolled;
- 기존 테이블 : 이미 존재하는 테이블에 쿼리 결과를 저장
INSERT INTO CourseIds (SELECT DISTINCT cid FROM enrolled);
Output Control
ORDER BY, LIMIT 등으로 쿼리 결과물을 컨트롤 할 수 있음.
Window Functions
연관된 튜플 set의 row들에 대해 sliding을 통한 계산을 수행.
aggregation과 달리 단일 row 결과로 압축되지 않음.
(모든 window function이 그런 건 아니지만) 개념적으로 window function은 다음 스텝으로 수행됨.
- 테이블을 파티셔닝
- 각 파티션을 정렬 (
ORDER BY절이 있다면) - 각 record마다 여러 record에 걸친 window를 생성
- 각 window에 대해 output 계산
Functions: 어떤 aggregation function도 사용 가능. 추가로 특별한 window function도 있음.
ROW_NUMBER: 현재 row의 번호RANK: 현재 row의 order position
ROW_NUMBER는 유니크한 번호를 반환하고, RANK는 같은 값에 대해서 같은 번호를 반환
Grouping:
OVER 절은 window function을 계산할 때 어떻게 튜플을 그룹핑할지 명시해줌.
PARTITION BY로 그룹핑 기준을 명시할 수 있음.
SELECT cid, sid, ROW_NUMBER() OVER (PARTITION BY cid)
FROM enrolled ORDER BY cid;
ORDER BY를 넣어서 deterministic한 순서를 보장할 수도 있음.
SELECT *, ROW_NUMBER() OVER (ORDER BY cid)
FROM enrolled ORDER BY cid;
주의:
- DBMS는 window function의 정렬 이후에
RANK를 계산한다. (ROW_NUMBER는 정렬 이전에 계산) - SQL 쿼리에서
WHERE절은 window function 계산 전에 처리되기 때문에,WHERE절에서 window function 결과 필드를 사용할 수 없음.
SELECT * FROM (
SELECT *, RANK() OVER (PARTITION BY cid
ORDER BY grade ASC) AS rank
FROM enrolled) AS ranking
WHERE ranking.rank = 2;
Nested Queries
단일 쿼리에서 복잡한 로직을 실행하기 위해 쿼리 안에서 또 다른 쿼리를 호출하는 방식. 중첩 쿼리는 종종 최적화하기 어렵다.
Inner query는 outer query scope에 있는 속성에 접근 가능하다. 역은 성립하지 않는다.
Inner query는 웬만한 곳에 넣을 수 있다.
SELECTOutput Targets:
SELECT (SELECT 1) AS one FROM student;
- FROM Clause:
SELECT name
FROM student AS s, (SELECT sid FROM enrolled) AS e
WHERE s.sid = e.sid;
- WHERE Clause:
SELECT name FROM student
WHERE sid IN (SELECT sid FROM enrolled);
Nested Query Results Expressions
ALL: 모든 서브쿼리 row들에 대해 성립해야 함.ANY: 최소 한 개의 서브쿼리 row에 대해 성립해야 함.IN:ANY()와 동일.EXISTS: 최소 한 개의 row가 존재해야 함.
Lateral Joins
LATERAL 오퍼레이터를 nested query에 붙이면 해당 쿼리 이전에 나온 newted 쿼리의 속성에 접근할 수 있음.
예시:
각 course에 등록한 학생의 수와 course별 평균 GPA를 계산하고, enrollment count에 대해 descending order로 정렬.
SELECT * FROM course AS c
LATERAL (SELECT COUNT(*) AS cnt FROM enrolled
WHERE enrolled.cid = c.cid) AS t1,
LATERAL (SELECT AVG(gpa) AS avg FROM student AS s
JOIN enrolled AS e ON s.sid = e.sid
WHERE e.cid = c.cid) AS t2;
- 각 중첩 쿼리에서
c.cid에 접근하기 위해LATERAL필요
Common Table Expressions (CTE)
단일 쿼리에 스코프가 제한되는 임시 테이블 같은 거로 생각할 수 있다.
WITH 절을 사용해 inner query의 결과를 임시 테이블로 바인딩할 수 있음.
WITH cteName AS (
SELECT 1
)
SELECT * FROM cteName;
WITH cteName (col1, col2) AS (
SELECT 1, 2
)
SELECT col1 + col2 FROM cteName;
WITH cte1 (col1) AS (SELECT 1), cte2 (col2) AS (SELECT 2)
SELECT * FROM cte1, cte2;
RECURSIVE 키워드를 WITH와 사용하면 CTE가 자기 자신을 참조하게 할 수 있음.
WITH RECURSIVE cteSource (counter) AS (
(SELECT 1)
UNION
(SELECT counter + 1 FROM cteSource
WHERE counter < 10)
)
SELECT * FROM cteSource;