데이터베이스 언어는 크게 DDL, DML, DCL(TCL)로 분류한다.
DDL(Data Definition Language, 데이터 정의어)
CREATE, ALTER, DROP, TRUNCATE
등이 있다.DML (Data Manipulation Language, 데이터 조작어)
SELECT, INSERT, UPDATE, DELETE
등이 있다.DCL(Data Control Language, 데이터 제어어)
GRANT, REVOKE, COMMIT, ROLLBACK
등이 있다SQL 예약어를 대문자로 표시하고 끝에 세미콜론(선택사항)을 붙이면 코드 가독성이 좋아진다.
SELECT 컬럼명 FROM 테이블명;
*
으로 쓰면 모든 컬럼을 조회한다는 의미이다. ,
를 넣으면 테이블에 있는 여러 개의 컬럼을 조회할 수 있다.from 테이블명
을 생략할 수 있다.SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] ]
[ HAVING condition ]
[ WINDOW window_name AS ( window_definition ) [, ...] ]
[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
[ OFFSET start [ ROW | ROWS ] ]
[ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES } ]
[ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]
DISTINCT
: 중복된 데이터를 제외하고 조회할 때 사용, 어떤 컬럼에서 고유한 값을 찾고 싶을 때 유용하다.
SELECT DISTINCT 컬럼명 FROM 테이블명;
SELECT DISTINCT(컬럼명) FROM 테이블명;
DISTINCT 바로 뒤에 컬럼명에 괄호를 씌워서 사용할 수도 있다. 괄호를 쓰나 안쓰나 결과는 같다.
COUNT
함수: 특정 쿼리 조건에 맞는 입력 행의 개수를 구하는데 사용한다.
COUNT(*)
로 모든 컬럼을 지정할 수 있다. 둘 다 결과는 동일하다.SELECT COUNT(컬럼) FROM 테이블명;
DISTINCT
와 많이 사용된다.SELECT COUNT(DISTINCT 컬럼명) FROM 테이블명;
WHERE
문: 컬럼에 조건을 지정하여 그에 맞는 행이 반환 되도록 한다.
SELECT column1, column2 FROM table WHERE conditions;
SELECT name, choice FROM table WHERE name = ‘David' AND choice = 'RED'
ORDER BY
문: 조회된 데이터를 기준에 맞게 정렬해준다.
SELECT column1, column2, … FROM table ORDER BY column_1 ASC / DESC
SELECT store_id, first_name, last_name FROM customer ORDER BY store_id ASC, first_name DESC;
LIMIT
: 쿼리로 반환 되는 행의 개수를 제한하는 명령어
SELECT * FROM table LIMIT 5;
SELECT customer_id FROM payment ORDER BY payment_date ASC limit 10;
BETWEEN
연산자: 값을 값 범위와 비교할 때 사용
value ≥ low AND value ≤ high
value BETWEEN low AND high
위와 같은 의미 이다. (low이상, high이하)value < low or value > high
value NOT BETWEEN low AND high
NOT을 이용한 반대 범위 지정(low 미달, high 초과)SELECT COUNT(*) FROM film WHERE rating = 'R' AND replacement_cost BETWEEN 5 AND 15;
BETWEEN '2007-02-01' AND '2007-02-14’
일 때 실제 시간 범위는 2007년 2월 1일 0시 ~ 2007년 2월 14일 0시 이다. 따라서 2007년 2월 14일 10시 같은 데이터는 조회 되지 않는다.IN
연산자: 어떤 값이 목록에 포함됐는지 확인할 때 사용한다.
SELECT color FROM table WHERE color IN ('red', 'blue');
SELECT color FROM table WHERE color NOT IN ('red', 'blue');
- NOT 연산자 사용SELECT * FROM payment where amount not in (0.99, 1.98, 1.99);
LIKE
, ILIKE
: 문자열 데이터에 대한 패턴 매칭을 수행하기 위한 명령어이다.
LIKE
는 대소문자를 구분하지만 ILIKE
는 구분하지 않는다.
%
): 어떤 문자열과도 일치_
): 어떤 문자와도 일치, _
의 개수에 따라 매칭되는 문자의 개수를 결정한다.WHERE name LIKE 'A%'
WHERE name LIKE '%a'
select * from customer where first_name like 'J%' and last_name ilike 's%';
WHERE title LIKE ‘Mission Impossible _’
_
을 쓸 수 있다. WHERE value LIKE 'Version#__'
: Version#10, Version#20 등이 모두 매칭된다.WHERE name LIKE '_her%'
: Cheryl, Theresa, Sherri 등이 모두 매칭된다데이터가 카테고리 별로 어떻게 분포되어 있는지 파악하기 위해 데이터를 집계하고 함수를 적용하는 명령어 이다.
특정 컬럼을 기준으로 동일한 값끼리 그룹화하여 집계할 때 유용하다.
예를 들어 밑의 표에서 카테고리가 A인 레코드의 값의 평균(AVG(), 9)이나 개수(COUNT(), 2개)를 구해야 할 때 GROUP BY를 사용할 수 있다.
카테고리 | 값 |
---|---|
A | 10 |
A | 8 |
B | 6 |
B | 12 |
집계함수의 종류
AVG()
: SELECT ROUND(AVG(replacement_cost), 2) FROM film;
COUNT()
: SELECT COUNT(*) FROM film;
MAX()
: SELECT MAX(replacement_cost) FROM film;
MIN()
: SELECT MIN(replacement_cost) FROM film;
SUM()
: SELECT SUM(replacement_cost) FROM film;
SELECT category_col, 집계함수(data_col) FROM table GROUP BY category_col;
GROUP BY절은 FROM문 바로 뒤 또는 WHERE문 바로 뒤에 위치해야 한다.
SELECT문에서 특정 컬럼을 조회한다면 그 컬럼이 GROUP BY절에 포함되야 한다. 단 집계함수는 GROUP BY절에 포함되지 않아도 된다.
SELECT company, division, SUM(sales) FROM finance_table GROUP BY company, division;
WHERE절에서는 집계함수를 쓸 수 없다. 대신 HAVING을 사용할 수 있다.
집계를 기반하여 정렬하려면 ORDER BY
절에서 전체 함수를 참조해야 한다.
SELECT company, SUM(sales) FROM finance_table GROUP BY company ORDER BY SUM(sales);
가장 많은 금액을 사용한 고객ID는?
SELECT customer_id, SUM(amount) FROM payment GROUP BY customer_id ORDER BY SUM(amount) DESC;
결제 날짜 별(DATE함수 사용) 결제 금액 합계를 구하고, 합계 내림차순으로 정렬하기
SELECT DATE(payment_date), SUM(amount) FROM payment GROUP BY DATE(payment_date) ORDER BY SUM(amount) DESC;
직원id별로 처리한 결제 건수는 몇 건인가?
SELECT count(*), staff_id FROM payment group by staff_id;
영화 등급별 평균 교체 비용은?
SELECT rating, ROUND(AVG(replacement_cost), 2) FROM film GROUP BY rating;
결제 금액 합계 기준 가장 많이 지출한 고객 id 5개 찾기
SELECT customer_id, SUM(amount) FROM payment GROUP BY customer_id ORDER BY SUM(amount) DESC LIMIT 5;
HAVING
절은 GROUP BY
절로 선택된 그룹에 대한 탐색 조건을 지정한다. 즉 GROUP BY
절에 대한 조건문이라고 할 수 있다. 따라서 HAVING
은 GROUP BY
가 있는 질의문에서만 사용이 가능하다.SELECT company, SUM(sales) FROM finance_table WHERE company != 'Google' GROUP BY company HAVING SUM(sales) > 1000;
SELECT customer_id, COUNT() FROM payment GROUP BY customer_id HAVING COUNT() >= 40
SELECT customer_id, SUM(amount) FROM payment WHERE staff_id = 2 GROUP BY customer_id HAVING SUM(amount) > 100
ON
: 조인에 대한 조건문WHERE
: 레코드에 대한 조건문HAVING
: GROUP BY
절에 대한 조건문AS
로 별칭을 만들 수 있다. 여기서 AS
를 생략할 수도 있다EXISTS
연산자는 외부 질의의 각 레코드에 대해 내부 질의의 결과에 레코드가 존재하면 true를 반환하고 없으면 false를 반환한다. NOT EXISTS
는 반대로 동작한다.INTERSECT
(교집합), EXCEPT
(차집합), EXISTS
, NOT EXISTS
연산자를 서브쿼리와 함께 쓸 수 있다.-- FROM subquery
SELECT column1, column2
FROM (
SELECT column1, column2
FROM table1
) AS subquery;
-- products 테이블에서 특정 가격 범위에 속하는 상품들의 평균 가격을 계산하는 예시
SELECT price_range, AVG(price) AS average_price
FROM (
SELECT
CASE
WHEN price < 50 THEN 'Cheap'
WHEN price >= 50 AND price < 100 THEN 'Moderate'
ELSE 'Expensive'
END AS price_range, price
FROM products
) AS subquery
GROUP BY price_range;
-- 학과별로 소속 교수의 평균 연봉이 7천만원 미만인 학과 중에서 가장 높은 학과의 평균 연봉 구하기
SELECT MAX(sq.평균연봉) AS 평균연봉
FROM (SELECT 소속학과, AVG(연봉) AS 평균연봉 FROM 교수 GROUP BY 소속학과) AS sq
WHERE sq.평균연봉 <= 70000000
-- WHERE subquery
SELECT column1, column2, ...
FROM table1
WHERE column1 IN (SELECT subquery_column FROM table2 WHERE condition);
-- 생활과학과 소속 학생 중 수강신청을 하지 않은 학생의 학생번호 구하기
SELECT a.학생번호
FROM 전공 AS a
WHERE a.학과이름='생활과학과'
AND NOT EXISTS (
SELECT 학생번호
FROM 수강 AS b
WHERE a.학생번호 = b.학생번호
);
SELECT customer_id, SUM(amount)
FROM payment WHERE staff_id = 2
GROUP BY customer_id
HAVING SUM(amount) > 110;
SELECT COUNT(*)
FROM film
WHERE title LIKE 'J%';
SELECT first_name, last_name
FROM customer
WHERE first_name LIKE 'E%' AND address_id < 500
ORDER BY customer_id DESC
LIMIT 1;
SELECT facid, SUM(slots) AS total_slots
FROM cd.bookings
WHERE starttime BETWEEN '2012-09-01' AND '2012-10-01'
GROUP BY facid
ORDER BY SUM(slots)
SELECT facid, SUM(slots) AS total_slots
FROM cd.bookings
GROUP BY facid
HAVING SUM(slots) > 1000
ORDER BY facid