MySQL 문법 1. Select 기본, 각종 연산자와 함수들

본 글은 갖고노는 MySQL 데이터베이스 by 얄코 강의를 수강하고 이를 정리한 글입니다.

RDBMS

관계형 데이터베이스 관리 시스템(RDBMS)는 표를 기준으로 데이터를 저장 및 관리하는 시스템을 의미한다. 역사적으로 오래 사용되어 왔고 많은 곳에서 사용되는, 가장 기본이 되는 데이터베이스 시스템이다. 트랜잭션 취소도 쉬워 안정적이고, 또한 데이터의 구조를 일관적으로 가져갈 수 있다는 장점때문에 널리 이용된다.

SQL이라는 데이터베이스 관리용 언어를 사용하게 되며, RDBMS의 대표적인 제품으로는 MySQL, PostgreSQL, MSSQL 등이 있다. 본 글은 MySQL에서 사용되는 SQL의 문법을 정리한 글이다.

한편 이 링크로 들어가면 MySQL 쿼리문을 실제로 시험해볼 수 있는 에디터가 나온다.

한편 일반적으로 SQL은 대소문자는 구분하지 않으나, 함수, 연산자 등은 일관되게 작성하는 것이 좋다. 예를 들어 SELECT * FROM Customers와 같이 연산자, 함수 등은 대문자로만 쓰는 형식이다.

Select - 원하는 정보 가져오기

1. Select 전반적인 기능

1. 테이블의 모든 정보 보기

*을 이용한다.

SELECT * FROM Customers;
CustomerID CustomerName ContactName Address City PostalCode Country
1 Alfreds Futterkiste Maria Anders Obere Str. 57 Berlin 12209 Germany
2 Ana Trujillo Emparedados y helados Ana Trujillo Avda. de la Constitución 2222 México D.F. 05021 Mexico
3 Antonio Moreno Taquería Antonio Moreno Mataderos 2312 México D.F. 05023 Mexico
4 Around the Horn Thomas Hardy 120 Hanover Sq. London WA1 1DP UK
5 Berglunds snabbköp Christina Berglund Berguvsvägen 8 Luleå S-958 22 Sweden

2. 원하는 컬럼(열) 정보 갖고 오기

한편, 일반적으로는 *을 이용해서 모든 정보를 갖고 오는 것은 좋지 않은 습관이다. 이보다는 주로 원하는 컬럼만을 명시적으로 갖고 오는 방식이 더 선호된다.

SELECT CustomerID, CustomerName, ContactName FROM Customers;
CustomerID CustomerName ContactName
1 Alfreds Futterkiste Maria Anders
2 Ana Trujillo Emparedados y helados Ana Trujillo
3 Antonio Moreno Taquería Antonio Moreno
4 Around the Horn Thomas Hardy
5 Berglunds snabbköp Christina Berglund

3. 원하는 조건의 행 갖고 오기

WHERE 문을 통해서 조건절을 추가할 수 있다.

SELECT CustomerId, CustomerName, ContactName, Country
FROM Customers
WHERE Country = 'Mexico' OR Country = 'UK'
CustomerId CustomerName ContactName Country
2 Ana Trujillo Emparedados y helados Ana Trujillo Mexico
3 Antonio Moreno Taquería Antonio Moreno Mexico
4 Around the Horn Thomas Hardy UK
11 B's Beverages Victoria Ashworth UK
13 Centro comercial Moctezuma Francisco Chang Mexico

4. 원하는 순서대로 데이터 정렬하기

ORDER BY를 이용하여 정렬을 수행할 수 있다. 이때 기본값은 오름차순(ASC)이고, 내림차순으로 정렬하려면 DESC을 사용해야 한다.

구분 기준 기본
ASC 오름차순 O
DESC 내림차순  
SELECT * FROM Products ORDER BY Price ASC
ProductID ProductName SupplierID CategoryID Unit Price
33 Geitost 15 4 500 g 2.50
24 Guaraná Fantástica 10 1 12 - 355 ml cans 4.50
13 Konbu 6 8 2 kg box 6.00
52 Filo Mix 24 5 16 - 2 kg boxes 7.00
54 Tourtière 25 6 16 pies 7.45
SELECT * FROM Products ORDER BY Price DESC
ProductID ProductName SupplierID CategoryID Unit Price
38 Côte de Blaye 18 1 12 - 75 cl bottles 263.50
29 Thüringer Rostbratwurst 12 6 50 bags x 30 sausgs. 123.79
9 Mishi Kobe Niku 4 6 18 - 500 g pkgs. 97.00
20 Sir Rodney's Marmalade 8 3 30 gift boxes 81.00

조합도 가능함

SELECT * FROM OrderDetails
ORDER BY ProductID ASC, Quantity DESC;
-- OrderDetail에서 우선 ProductID를 기준으로 오름차순 정렬 후
-- 같은 ProductID에 대해서는 Quantity를 기준으로 내림차순 정렬
OrderDetailID OrderID ProductID Quantity
1570 10847 1 80
1741 10918 1 60
1271 10729 1 50
100 10285 1 45
2022 11031 1 45

5. 원하는 행 개수만 가져오기 (Pagination에 활용)

LIMIT을 통해서 원하는 행 개수만 가져올 수 있다.

SELECT ProductID, ProductName, Price FROM Products
LIMIT 3
-- 최대 3개까지만 갖고 오기
ProductID ProductName Price
1 Chais 18.00
2 Chang 19.00
3 Aniseed Syrup 10.00
SELECT ProductID, ProductName, Price FROM Products
LIMIT 3, 3
-- 3 초과부터 3개 더 갖고 오기
ProductID ProductName Price
4 Chef Anton's Cajun Seasoning 22.00
5 Chef Anton's Gumbo Mix 21.35
6 Grandma's Boysenberry Spread 25.00
     

보통 이 방식은 페이지네이션에서 자주 활용된다. 예를 들어서, 어떤 인터넷 포스트들을 보는데, 포스트가 1000개가 있다면 이를 한 번에 불러오는 것은 매우 비효율적이다. 1페이지에 50개, 2페이지에 50개, ... 이런 식으로 페이지를 나누는 게 훨씬 현명한 방법일 것이다. 이때 페이지네이션을 구현하기 위해 제한된 개수의 데이터만을 불러오는 LIMIT을 사용한다.

6. 원하는 컬럼 명으로 갖고 오기

가독성을 위해서 사용한다.

SELECT CustomerID AS Uid,
CustomerName AS Name,
Address AS Addr
FROM Customers
LIMIT 5
Uid Name Addr
1 Alfreds Futterkiste Obere Str. 57
2 Ana Trujillo Emparedados y helados Avda. de la Constitución 2222
3 Antonio Moreno Taquería Mataderos 2312
4 Around the Horn 120 Hanover Sq.
5 Berglunds snabbköp Berguvsvägen 8

한국어는 ‘’ 표로 문자열로 만들면 된다.

SELECT CustomerID AS Uid,
CustomerName AS '고객명',
Address AS '주소'
FROM Customers
LIMIT 5
Uid 고객명 주소
1 Alfreds Futterkiste Obere Str. 57
2 Ana Trujillo Emparedados y helados Avda. de la Constitución 2222
3 Antonio Moreno Taquería Mataderos 2312
4 Around the Horn 120 Hanover Sq.
5 Berglunds snabbköp Berguvsvägen 8

2. 각종 연산자들

연산자 의미
+, -, *, / 각각 더하기, 빼기, 곱하기, 나누기
%, MOD 나머지
IS 양쪽이 모두 TRUE 또는 FALSE
IS NOT 한쪽은 TRUE, 한쪽은 FALSE
AND, && 양쪽이 모두 TRUE일 때만 TRUE
OR,  
= 양쪽 값이 같음
!=, <> 양쪽 값이 다름
>, < (왼쪽, 오른쪽) 값이 더 큼
>=, <= (왼쪽, 오른쪽) 값이 같거나 더 큼
BETWEEN {MIN} AND {MAX} 두 값 사이에 있음
NOT BETWEEN {MIN} AND {MAX} 두 값 사이가 아닌 곳에 있음
IN (...) 괄호 안의 값들 가운데 있음
NOT IN (...) 괄호 안의 값들 가운데 없음
LIKE '... % ...' 0~N개 문자를 가진 패턴
LIKE '... _ ...' _ 갯수만큼의 문자를 가진 패턴

LIKE는 문자열 속 포함 관계 혹은 패턴 검색을 위해 자주 사용한다.

SELECT * FROM Customers WHERE CustomerName LIKE 'b%'
-- b로 시작하는 이름의 Customer 갖고 오기
SELECT * FROM Customers WHERE CustomerName BETWEEN 'b' AND 'c'
-- 위와 같은 의미임
CustomerID CustomerName ContactName Address City PostalCode Country
5 Berglunds snabbköp Christina Berglund Berguvsvägen 8 Luleå S-958 22 Sweden
6 Blauer See Delikatessen Hanna Moos Forsterstr. 57 Mannheim 68306 Germany
7 Blondel père et fils Frédérique Citeaux 24, place Kléber Strasbourg 67000 France
8 Bólido Comidas preparadas Martín Sommer C/ Araquil, 67 Madrid 28023 Spain
9 Bon app' Laurence Lebihans 12, rue des Bouchers Marseille 13008 France
10 Bottom-Dollar Marketse Elizabeth Lincoln 23 Tsawassen Blvd. Tsawassen T2F 8M4 Canada
11 B's Beverages Victoria Ashworth Fauntleroy Circus London EC2 5NT UK

3. 숫자와 문자열을 다루는 함수들

1. 숫자 관련 함수들

MySQL :: MySQL 8.0 Reference Manual :: 12.6 Numeric Functions and Operators

함수 설명
ROUND 반올림
CEIL 올림
FLOOR 내림
ABS 절대값
SELECT 
  ROUND(0.5), -- 1
  CEIL(0.4), -- 1
  FLOOR(0.6); -- 0
SELECT * FROM OrderDetails
WHERE ABS(Quantity - 10) < 5;
OrderDetailID OrderID ProductID Quantity
1 10248 11 12
2 10248 42 10
4 10249 14 9
6 10250 41 10

함수 설명
GREATEST (괄호 안에서) 가장 큰 값
LEAST (괄호 안에서) 가장 작은 값

**MAX, MIN과 헷갈리지 말기**
GREATEST, LEAST는 괄호(리스트) 안에서 가장 큰, 작은 값을 찾는 함수이고, MAX, MIN은 컬럼 중에서 max, min을 찾는 함수

SELECT
  OrderDetailID, ProductID, Quantity,
  GREATEST(OrderDetailID, ProductID, Quantity) AS Greatest,
  LEAST(OrderDetailID, ProductID, Quantity) AS Least
FROM OrderDetails;
OrderDetailID ProductID Quantity Greatest Least
1 11 12 12 1
2 42 10 42 2
3 72 5 72 3
4 14 9 14 4

함수 설명
MAX 가장 큰 값
MIN 가장 작은 값
COUNT 갯수 (NULL값 제외)
SUM 총합
AVG 평균 값
SELECT
  MAX(Quantity),
  MIN(Quantity),
  COUNT(Quantity),
  SUM(Quantity),
  AVG(Quantity)
FROM OrderDetails
WHERE OrderDetailID BETWEEN 20 AND 30;
MAX(Quantity) MIN(Quantity) COUNT(Quantity) SUM(Quantity) AVG(Quantity)
50 6 11 254 23.0909

함수 설명
POW(A, B), POWER(A, B) A를 B만큼 제곱
SQRT 제곱근

함수 설명
TRUNCATE(N, n) N을 소숫점 n자리까지 선택
SELECT
  TRUNCATE(1234.5678, 1), -- 1234.5
  TRUNCATE(1234.5678, 2), -- 1234.56
  TRUNCATE(1234.5678, 3), -- 1234.567
  TRUNCATE(1234.5678, -1), -- 1230
  TRUNCATE(1234.5678, -2), -- 1200
  TRUNCATE(1234.5678, -3); -- 1000

SQL은 1부터 센다. 1이면 소수 첫 번째 자리까지 표기, 나머지는 버린다(반올림 X, 그냥 버린다는 것에 주의)

-1이면 양수 기준 1번 째 자리부터 버리기

SELECT Price FROM Products
WHERE TRUNCATE(Price, 0) = 12;
-- 12.00번 대의 Price를 가진 상품을 갖고 옴
-- WHERE Price >= 12 AND Price < 13과 같은 의미
ProductName Price
Gorgonzola Telino 12.50
Spegesild 12.00
Chocolade 12.75
Scottish Longbreads 12.50

2. 문자열 관련 함수들

함수 설명
UCASE, UPPER 모두 대문자로
LCASE, LOWER 모두 소문자로

함수 설명
CONCAT(...) 괄호 안의 내용 이어붙임
CONCAT_WS(S, ...) 괄호 안의 내용 S로 이어붙임
SELECT CONCAT('HELLO', ' ', 'THIS IS ', 2021)
-- HELLO THIS IS 2021
-- CONCAT 함수에서 숫자는 알아서 문자열로 바꾸어 붙임

SELECT CONCAT_WS('-', 2021, 8, 15, 'AM')
-- 2021-8-15-AM
SELECT CONCAT('O-ID: ', OrderID) FROM Orders;
CONCAT('O-ID: ', OrderID)
O-ID: 10248
O-ID: 10249
O-ID: 10250
O-ID: 10251
SELECT
  CONCAT_WS(' ', FirstName, LastName) AS FullName,
  FirstName, LastName
FROM Employees;
FullName FirstName LastName
Nancy Davolio Nancy Davolio
Andrew Fuller Andrew Fuller
Janet Leverling Janet Leverling

함수 설명
SUBSTR, SUBSTRING 주어진 값에 따라 문자열 자름
LEFT 왼쪽부터 N글자
RIGHT 오른쪽부터 N글자
SELECT
  SUBSTR('ABCDEFG', 3), -- CDEFG, SQL은 1부터 숫자 셈(3번 째 문자인 C부터 자르기 시작)
  SUBSTR('ABCDEFG', 3, 2), -- CD, 3번째 글자인 C부터 2개인 C, D
  SUBSTR('ABCDEFG', -4), -- DEFG, 뒤에서 네 번째부터 자르기
  SUBSTR('ABCDEFG', -4, 2), -- DE, 뒤에서 네 번째부터 두 개 자르기
  LEFT('ABCDEFG', 3), -- ABC
  RIGHT('ABCDEFG', 3); -- EFG
SELECT
  OrderDate,
  LEFT(OrderDate, 4) AS Year,
  SUBSTR(OrderDate, 6, 2) AS Month,
  RIGHT(OrderDate, 2) AS Day
FROM Orders;
OrderDate Year Month Day
1996-07-04 1996 07 04
1996-07-05 1996 07 05
1996-07-08 1996 07 08

함수 설명
LENGTH 문자열의 바이트 길이
CHAR_LENGTH, CHARACTER_LEGNTH 문자열의 문자 길이
-- w3wchool 사이트에서는 한글이 제대로 동작하지 않습니다.
SELECT
  LENGTH('안녕하세요'), -- 15
  CHAR_LENGTH('안녕하세요'), -- 5
  CHARACTER_LENGTH('안녕하세요'); -- 5

4. 시간/날짜 관련 및 기타 함수들

함수 설명
CURRENT_DATE, CURDATE 현재 날짜 반환
CURRENT_TIME, CURTIME 현재 시간 반환
CURRENT_TIMESTAMP, NOW 현재 시간과 날짜 반환
SELECT CURDATE(), CURTIME(), NOW();
함수 설명
DATE 문자열에 따라 날짜 생성
TIME 문자열에 따라 시간 생성
YEAR 주어진 DATETIME값의 년도 반환
MONTHNAME 주어진 DATETIME값의 월(영문) 반환
MONTH 주어진 DATETIME값의 월 반환
WEEKDAY 주어진 DATETIME값의 요일값 반환(월요일: 0)
DAYNAME 주어진 DATETIME값의 요일명 반환
DAYOFMONTH, DAY 주어진 DATETIME값의 날짜(일) 반환
LAST_DAY 해당 달의 마지막 날짜
HOUR 주어진 DATETIME의 시 반환
MINUTE 주어진 DATETIME의 분 반환
SECOND 주어진 DATETIME의 초 반환

DATE와 TIME이 반환하는 타입은 서로 다른 타입이라는 것에 주의하자. 비교 연산 시 서로 타입이여야 제대로 비교 연산이 작동한다.

SELECT
  OrderDate,
  CONCAT(
    CONCAT_WS(
      '/',
      YEAR(OrderDate), MONTH(OrderDate), DAY(OrderDate)
    ),
    ' ',
    UPPER(LEFT(DAYNAME(OrderDate), 3))
  ) AS Concat
FROM Orders;
OrderDate Concat
1996-07-04 1996/7/4 THU
1996-07-05 1996/7/5 FRI
1996-07-08 1996/7/8 MON

함수 설명
ADDDATE, DATE_ADD 시간/날짜 더하기
SUBDATE, DATE_SUB 시간/날짜 빼기
SELECT 
  ADDDATE('2021-06-20', INTERVAL 1 YEAR),
  ADDDATE('2021-06-20', INTERVAL -2 MONTH),
  ADDDATE('2021-06-20', INTERVAL 3 WEEK),
  ADDDATE('2021-06-20', INTERVAL -4 DAY),
  ADDDATE('2021-06-20', INTERVAL -5 MINUTE),
  ADDDATE('2021-06-20 13:01:12', INTERVAL 6 SECOND);

INTERVALADDDATE 함수에서 사용하는 범위 및 시간 간격을 나타내는 키워드


함수 설명
DATE_DIFF 두 시간/날짜 간 일수차
TIME_DIFF 두 시간/날짜 간 시간차
SELECT * FROM Orders
WHERE
  ABS(DATEDIFF(OrderDate, '1996-10-10')) < 5;
-- 1996-10-10일로부터 ± 5일 미만의 Order 표시
OrderID CustomerID EmployeeID OrderDate ShipperID
10323 39 4 1996-10-07 1
10324 71 9 1996-10-08 1
10325 39 1 1996-10-09 3

함수 설명
DATE_FORMAT 시간/날짜를 지정한 형식으로 반환
형식 설명
%Y 년도 4자리
%y 년도 2자리
%M 월 영문
%m 월 숫자
%D 일 영문(1st, 2nd, 3rd...)
%d, %e 일 숫자 (01 ~ 31)
%T hh:mm:ss
%r hh:mm:ss AM/PM
%H, %k 시 (~23)
%h, %l 시 (~12)
%i
%S, %s
%p AM/PM
SELECT
  DATE_FORMAT(NOW(), '%M %D, %Y %T'),
  DATE_FORMAT(NOW(), '%y-%m-%d %h:%i:%s %p'),
  DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %s초');
DATE_FORMAT(NOW(), '%M %D, %Y %T') DATE_FORMAT(NOW(), '%y-%m-%d %h:%i:%s %p') DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %s초')
July 4th, 2023 04:59:41 23-07-04 04:59:41 AM 2023년 07월 04일 AM 04시 59분 41초
SELECT REPLACE(
  REPLACE(
    DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %초'),
    'AM', '오전'
  ),
  'PM', '오후'
)
-- 2023년 07월 04일 오전 05시 00분 초
-- 'AM'을 먼저 오전으로 바꾼 후, PM을 오후로 바꾼다. 
-- 어차피 AM, PM 둘 중 하나만 존재하므로 이런 식으로 SQL을 짤 수 있다

함수 설명
STR _ TO _ DATE(S, F) S를 F형식으로 해석하여 시간/날짜 생성
SELECT
  DATEDIFF(
    STR_TO_DATE('2021-06-04 07:48:52', '%Y-%m-%d %T'),
    STR_TO_DATE('2021-06-01 12:30:05', '%Y-%m-%d %T')
  ), -- 3, DATE니깐 3일 차이남
  TIMEDIFF(
    STR_TO_DATE('2021-06-04 07:48:52', '%Y-%m-%d %T'),
    STR_TO_DATE('2021-06-01 12:30:05', '%Y-%m-%d %T')
  ); -- 67:18:47, TIME 시간 차이는 이만큼 차이남
SELECT
  OrderDate,
  DATEDIFF(
    STR_TO_DATE('1997-01-01 13:24:35', '%Y-%m-%d %T'),
    OrderDate
  ) AS DateDiff,
  TIMEDIFF(
    STR_TO_DATE('1997-01-01 13:24:35', '%Y-%m-%d %T'),
    STR_TO_DATE(CONCAT(OrderDate, ' ', '00:00:00'), '%Y-%m-%d %T')
  ) AS TimeDiff
FROM Orders;
OrderDate DateDiff TimeDiff
1996-07-04 181 838:59:59
1996-07-05 180 838:59:59

IF/IFNULL

형식 설명
IF(조건, T, F) 조건이 참이라면 T, 거짓이면 F 반환
IFNULL(A, B) A가 NULL일 시 B 출력

보다 복잡한 조건문은 CASE를 사용한다

SELECT
  Price,
  IF (Price > 30, 'Expensive', 'Cheap') AS ExpensiveOrCheap,
  CASE
    WHEN Price < 20 THEN '저가'
    WHEN Price BETWEEN 20 AND 30 THEN '일반'
    ELSE '고가'
  END AS '가격 구분'
FROM Products;
Price ExpensiveOrCheap 가격 구분
18.00 Cheap 저가
19.00 Cheap 저가
10.00 Cheap 저가
22.00 Cheap 일반

5. 조건에 따라 그룹으로 묶기

Lesson 5. 조건에 따라 그룹으로 묶기

  • 그룹 함수
함수 설명
MAX 가장 큰 값
MIN 가장 작은 값
COUNT 갯수 (NULL값 제외)
SUM 총합
AVG 평균 값

이 그룹 함수들은 GROUP BY 라는 키워드와 함께 자주 사용된다

GROUP BY 는 조건에 따라 집계된 값을 가져온다.

SELECT Country FROM Customers
GROUP BY Country;

21개 국가 명단 →

Country
Argentina
Austria
Belgium
Brazil
SELECT 
  Country, City,
  CONCAT_WS(', ', City, Country)
FROM Customers
GROUP BY Country, City;

두 개의 컬럼을 기준으로 그룹도 가능함

Country City CONCAT_WS(', ', City, Country)
Argentina Buenos Aires Buenos Aires, Argentina
Austria Graz Graz, Austria
Austria Salzburg Salzburg, Austria

그룹 함수 활용하기

SELECT
  COUNT(*), OrderDate
FROM Orders
GROUP BY OrderDate;

OrderDate로 그룹화해서, 각 OrderDate에 몇 개의 Order가 들어가있는지 집계하기

COUNT(*) OrderDate
1 1996-07-04
1 1996-07-05
2 1996-07-08
1 1996-07-09

SELECT
  ProductID,
  SUM(Quantity) AS QuantitySum
FROM OrderDetails
GROUP BY ProductID
ORDER BY QuantitySum DESC;

각 ProductID 별로 몇 개의 Quantity가 있는지 SUM으로 집계 후, QuantitySum으로 내림차순 정렬

ProductID QuantitySum
60 1577
59 1496
31 1397

SELECT
  CategoryID,
  MAX(Price) AS MaxPrice, 
  MIN(Price) AS MinPrice,
  TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
  TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
GROUP BY CategoryID
WITH ROLLUP -- 맨 밑에 집계용
-- 각 컬럼에 대해 전체 행 중 Max, Min, Median, Avg 값을 구한 것을 확인할 수 있음

각 CategoryID별로 그룹화해서, 각 카테고리 아이디별 Max, Min, Med, Avg 값을 구함

CategoryID MaxPrice MinPrice MedianPrice AveragePrice
1 263.50 4.50 134.00 37.97
2 43.90 10.00 26.95 23.06
3 81.00 9.20 45.10 25.16
4 55.00 2.50 28.75 28.73
5 38.00 7.00 22.50 20.25
6 123.79 7.45 65.62 54.00
7 53.00 10.00 31.50 32.37
8 62.50 6.00 34.25 20.68
  263.50 2.50 133.00 28.86
SELECT 
  CONCAT_WS(', ', City, Country) AS Location,
  COUNT(CustomerID)
FROM Customers
GROUP BY Country, City
WITH ROLLUP;
Location COUNT(CustomerID)
Buenos Aires, Argentina 3
Graz, Austria 1
Salzburg, Austria 1
  91

Country, City로 그룹화해서, 각 Location 당 몇 명의 Customer가 있는지 집계

HAVING 으로 그룹화된 데이터 걸러내기

SELECT
  Country, COUNT(*) AS Count
FROM Suppliers
GROUP BY Country
HAVING Count >= 3;
-- Supplier 중에서 Count가 3 이상인 Country만 표시
Country Count
France 3
Germany 3
USA 4
SELECT
  COUNT(*) AS Count, OrderDate
FROM Orders
WHERE OrderDate > DATE('1996-12-31')
GROUP BY OrderDate
HAVING Count > 2;
-- 1996년 12월 31일 이후의 Order 중에서, Order 개수(Count)가 2 이상인 날짜만 Select
Count OrderDate
3 1997-12-16
3 1997-12-18
3 1997-12-22
SELECT
  CategoryID,
  MAX(Price) AS MaxPrice, 
  MIN(Price) AS MinPrice,
  TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
  TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
WHERE CategoryID > 2
GROUP BY CategoryID
HAVING
  AveragePrice BETWEEN 20 AND 30
  AND MedianPrice < 40;
-- CategoryID가 2 이상인 Product로부터 Avg가 20부터 30 사이, Med가 40 이하인 Product만 Select
CategoryID MaxPrice MinPrice MedianPrice AveragePrice
4 55.00 2.50 28.75 28.73
5 38.00 7.00 22.50 20.25
8 62.50 6.00 34.25 20.68

DISTINCT: 중복된 값들 제거

SELECT DISTINCT CategoryID
FROM Products;
-- 위의 GROUP BY를 사용한 쿼리와 결과 비교 시
-- 정렬되지 않았음을 확인할 수 있다.

-- SELECT CategoryID FROM Products GROUP BY CategoryID -- 정렬됨
CategoryID
1
2
7

DISTINCT는 집계 함수와 사용 불가능하다. 즉 아래 문장은 오류가 발생한다. (단, ORDER BY 는 사용 가능하다)

SELECT COUNT DISTINCT CategoryID
FROM Products;
-- 오류 발생

SELECT DISTINCT Country, City
FROM Customers
ORDER BY Country, City;
Country City
Argentina Buenos Aires
Austria Graz
Austria Salzburg

DISTINCTGROUP BY의 사용:

SELECT
  Country,
  COUNT(DISTINCT CITY)
FROM Customers
GROUP BY Country
WITH ROLLUP;
-- 각 Customer의 Country 중에서, 중복되지 않은 City의 수를 센다
Country COUNT(DISTINCT CITY)
Argentina 1
Austria 2
Belgium 2
Brazil 4
 
  69

밑에 ROLLUP을 보면 총 69개의 City가 존재함을 알 수 있다.


 

Reference