💡 유튜브 채널 ‘얄팍한 코딩사전’에서 제공하는 강좌를 보고 학습했습니다.
SQL의 기초적인 내용을 웹에서 실습해볼 수 있는 강좌입니다.
강좌에서 배운 개념을 바탕으로 직접 문제를 만들고, 이를 풀어보는 식으로 독학했습니다.
강좌 링크
얄코의 갖고 노는 MySQL 데이터베이스 강좌
실습 웹사이트 링크
MySQL Tryit Editor v1.0
1. SELECT기초 - 원하는 정보 가져오기
1-3 숫자와 문자열을 다루는 함수들
숫자 관련 함수들
함수 |
설명 |
ROUND |
반올림 |
CEIL |
올림 |
FLOOR |
내림 |
ABS |
절댓값 |
GREATEST |
괄호안에서 최댓값 |
LEAST |
괄호안에서 최솟값 |
select round(0.5), --반올림
ceil(0.4), --올림
floor(0.6), --내림
abs(-1), -- 절댓값
greatest(1,2,3), --괄호 안에서 최댓값.
least(1,2,3), --괄호 안에서 최솟값.
이 때 헷갈려서는 안 될 것이 greatest
와 max
그리고 least
와 min
의 차이이다. greatest
, least
는 괄호 안에 있는 것 중에서 최대최소를 찾는 것이라면, max
와 min
은 특정 컬럼 내에서 최댓값 혹은 최솟값을 갖는 열을 찾는 것이다.
함수 |
설명 |
MAX |
가장 큰 값 |
MIN |
가장 작은 값 |
COUNT |
갯수 (NULL값 제외) |
SUM |
총합 |
AVG |
평균 값 |
select
max(quantity), -- 최댓값
min(quantity), -- 최솟값
count(quantity), -- NULL을 제외한 개수
sum(quantity), -- 총합
avg(quantity) -- 평균
from OrderDetails;
❓ 문제.
Products 테이블에서 Price의 평균, 최댓값, 최솟값을 출력하라.
이 때 각 값들은 반올림하도록 한다.
💡 답.
SELECT
round(avg(Price)) as '평균가격',
round(max(Price)) as '최대가격',
round(min(Price)) as '최소가격'
from Products;
함수 |
설명 |
POW(A, B), POWER(A, B) |
A를 B만큼 제곱 |
SQRT |
제곱근 |
TRUNCATE(N, n) |
N을 소숫점 n자리까지 선택 |
SELECT
power(2,2), -- 2의 2제곱
pow(2,2), -- 2의 2제곱
sqrt(4), --4의 제곱근
truncate(123.4567, 1) --123.4 소수점 첫째짜리까지 출력(그 뒤는 버림)
truncate(123.4567, 1) --120 일의 자리에서 버림
문자열 관련 함수들
함수 |
설명 |
UCASE, UPPER |
모두 대문자로 |
LCASE, LOWER |
모두 소문자로 |
SELECT
upper('abc'), -- 모두 대문자로
ucase('abc'), -- 모두 대문자로
lower('ABC'), -- 모두 소문자로
lcase('ABC'); -- 모두 소문자로
❓ 문제.
Suppliers 테이블에서 City는 대문자로, Address는 소문자로 출력하고,
SupplierName을 내림차순으로 정렬하라.
💡 답.
SELECT
SupplierName,
upper(City),
lower(Address)
FROM Suppliers
order by SupplierName desc;
함수 |
설명 |
CONCAT(…) |
괄호 안의 내용 이어붙임 |
CONCAT_WS(S, …) |
괄호 안의 내용 S로 이어붙임 |
SELECT
concat('hi', ' ', 'this is ', 2022), --괄호 안의 원소를 이어붙인다.
concat_ws('-', 2022, 02, 08); --괄호 안의 원소를 맨 처음 원소로 이어붙인다.
❓ 문제.
Customers 테이블에서 Country와 City를 컴마로 묶어서 불러오자(location으로 컬럼명 변경).
이 때 Country를 오름차순으로 정렬하고 그 후에 City를 오름차순으로 정렬한다.
💡 답.
SELECT
CustomerName,
concat_ws(', ', City, Country)
FROM Customers
order by Country, City;
함수 |
설명 |
SUBSTR, SUBSTRING |
주어진 값에 따라 문자열 자름 |
LEFT |
왼쪽부터 N글자 |
RIGHT |
오른쪽부터 N글자 |
SELECT
substr('heejun', 3), -- ejun 3번째 단어부터만 출력
substr('heejun', 3, 2), -- ej 3번째 단어부터 2개만 출력
substr('heejun', -4), -- ejun 뒤에서 4번째 단어부터 출력
substr('heejun', -4, 2), -- ej 뒤에서 4번째 단어부터 2개만 출력
left('heejun', 3), -- 왼쪽부터 3글자
right('heejun', 3); -- 오른쪽부터 3글자
select
OrderDate,
LEFT(OrderDate, 4) AS YEAR,
SUBSTR(OrderDate, 6, 2) AS Month,
RIGHT(OrderDate, 2) AS Day
FROM Orders;
함수 |
설명 |
LENGTH |
문자열의 바이트 길이 |
CHAR_LENGTH, CHARACTER_LEGNTH |
문자열의 문자 길이 |
문자열의 길이를 출력하려면 그냥 LENGTH
가 아니라 CHAR_LENGTH
를 써야 한다!
SELECT
LENGTH('안녕하세요'), -- 15
CHAR_LENGTH('안녕하세요'); -- 5
함수 |
설명 |
TRIM |
양쪽 공백 제거 |
LTRIM |
왼쪽 공백 제거 |
RTRIM |
오른쪽 공백 제거 |
함수 |
설명 |
LPAD(S, N, P) |
S가 N글자가 될 때까지 P를 왼쪽에 이어붙임 |
RPAD(S, N, P) |
S가 N글자가 될 때까지 P를 오른쪽에 이어붙임 |
SELECT
LPAD('ABC', 5, '*'), -- **ABC
RPAD('ABC', 5, '-'); -- ABC**
함수 |
설명 |
REPLACE(S, A, B) |
S중 A를 B로 변경 |
❓ 문제.
Employees 테이블에서 생년월일을 yy.mm.dd. 형식으로 바꾸고,
LastName, FirstName과 함께 출력하라.
💡 답.
SELECT
LastName,
FirstName,
concat(replace(substr(BirthDate, 3), '-', '.'),'.') as Birthdate
FROM Employees;
함수 |
설명 |
INSTR(S, s) |
S중 s의 첫 위치 반환, 없을 시 0 |
SELECT * FROM Customers
WHERE INSTR(CustomerName, ' ') BETWEEN 1 AND 6; -- CustomerName의 첫글자가 6보다 짧은 것만 출력.
함수 |
설명 |
Convert(A, T) |
A를 T 자료형으로 변환 |
SELECT
'01' = '1', -- false(0)
convert('01', decimal) = convert('1', decimal); -- true(1)
--문자열을 decimal(숫자 자료형)으로 변환
1-4 시간/날짜 관련 및 기타 함수들
함수 |
설명 |
CURRENT_DATE, CURDATE |
현재 날짜 반환 |
CURRENT_TIME, CURTIME |
현재 시간 반환 |
CURRENT_TIMESTAMP, NOW |
현재 시간과 날짜 반환 |
SELECT
CURDATE(), -- 2022-02-09
CURTIME(), -- 08:25:55
NOW(); -- 2022-02-09 08:25:55
함수 |
설명 |
DATE |
문자열에 따라 날짜 생성 |
TIME |
문자열에 따라 시간 생성 |
만약에 DATE
함수에 시간과 날짜를 모두 입력한다면, 날짜만 불러온다. 마찬가지로 TIME
함수에 시간과 날짜를 모두 입력한다면, 시간만 불러온다. 이 때 함수에는 ‘문자열’형식으로 입력해줘야 한다.
SELECT
'2021-6-1 1:2:3' = '2021-06-01 01:02:03', -- 0
DATE('2021-6-1 1:2:3') = DATE('2021-06-01 01:02:03'), -- 1
TIME('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'), -- 1
DATE('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'), -- 0 DATE는 날짜만 가져오고, TIME은 시간만 가져온다.
DATE('2021-6-1') = DATE('2021-06-01 01:02:03'), -- 1
TIME('2021-6-1 1:2:3') = TIME('01:02:03'); -- 1
❓ 문제.
Orders 테이블에서 주문날짜가 1997년 3월부터 1998년 4월까지인 것 중
ShipperID가 1인 것만을 불러오자.
💡 답.
SELECT *
FROM Orders
WHERE
OrderDate BETWEEN DATE('1997-3-1') AND DATE('1998-4-30') and
ShipperID=1
함수 |
설명 |
YEAR |
주어진 DATETIME값의 년도 반환 |
MONTHNAME |
주어진 DATETIME값의 월(영문) 반환 |
MONTH |
주어진 DATETIME값의 월 반환 |
WEEKDAY |
주어진 DATETIME값의 요일값 반환(월요일: 0) |
DAYNAME |
주어진 DATETIME값의 요일명 반환 |
DAYOFMONTH, DAY |
주어진 DATETIME값의 날짜(일) 반환 |
SELECT
OrderDate,
CONCAT(CONCAT_WS('/', YEAR(OrderDate), MONTH(OrderDate), DAY(OrderDate)),
' ', UPPER(LEFT(DAYNAME(OrderDate),3))) AS orderdate
FROM Orders;
함수 |
설명 |
HOUR |
주어진 DATETIME의 시 반환 |
MINUTE |
주어진 DATETIME의 분 반환 |
SECOND |
주어진 DATETIME의 초 반환 |
SELECT
HOUR(NOW()), MINUTE(NOW()), SECOND(NOW());
함수 |
설명 |
ADDDATE, DATE_ADD |
시간/날짜 더하기 |
SUBDATE, DATE_SUB |
시간/날짜 빼기 |
SELECT
ADDDATE('2022-02-09', INTERVAL 1 YEAR),
ADDDATE('2022-02-09', INTERVAL -2 MONTH),
ADDDATE('2021-02-09', INTERVAL 3 WEEK);
함수 |
설명 |
DATE_DIFF |
두 시간/날짜 간 일수차 |
TIME_DIFF |
두 시간/날짜 간 시간차 |
SELECT
OrderDate,
NOW(),
DATEDIFF(OrderDate, NOW())
FROM Orders;
❓ 문제.
1998년 2월 10일은 구정이다.
Orders 테이블에서 구정 앞뒤 1주일의 기간동안 주문한 상품은 배송이 지연될 것으로 예상된다.
주문이 지연되는 상품들만 불러오자.
💡 답.
SELECT * FROM Orders
WHERE abs(datediff(OrderDate, '1998-02-10')) <= 7;
함수 |
설명 |
LAST_DAY |
해당 달의 마지막 날짜 |
LAST_DAY
함수는 해당 달의 마지막 날짜를 불러오는데, 만약 LAST
SELECT
OrderDate,
LAST_DAY(OrderDate),
DAY(LAST_DAY(OrderDate)),
DATEDIFF(LAST_DAY(OrderDate), OrderDate)
FROM Orders;
함수 |
설명 |
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, %r') AS "1",
DATE_FORMAT(NOW(), '%Y년 %m월 %d일, %p %h시 %i분') AS "3",
DATE_FORMAT(NOW(), '%M %d, %y, %H:%i') AS "A";
함수 |
설명 |
STR _ TO _ DATE(S, F) |
S를 F형식으로 해석하여 시간/날짜 생성 |
SELECT
DATEDIFF(STR_TO_DATE('2022-10-11 07:48:52', '%Y-%m-%d %T'),
STR_TO_DATE('2022-02-10 22:10:52', '%Y-%m-%d %T')),
TIMEDIFF(STR_TO_DATE('2022-10-11 07:48:52', '%Y-%m-%d %T'),
STR_TO_DATE('2022-02-10 22:10:52', '%Y-%m-%d %T'));
형식 |
설명 |
IF(조건, T, F) |
조건이 참이라면 T, 거짓이면 F 반환 |
SELECT IF (1 > 2, '1는 2보다 크다.', '1은 2보다 작다.');
#보다 복잡한 조건은 CASE문을 사용한다. 들여쓰기 할 필요가 없다.
SELECT
CASE
WHEN -1 > 0 THEN '-1은 양수다.'
WHEN -1 = 0 THEN '-1은 0이다.'
ELSE '-1은 음수다.'
END;
❓ 문제.
OrderDetails 테이블에서 Quantity가 45 이상이면 ‘초대량주문’, 20 이상 45 미만이면 ‘대량주문’, 20 미만이면 ‘일반주문’으로 표시되도록 하자.
💡 답.
SELECT
OrderID,
Quantity,
CASE
WHEN Quantity >= 45 THEN '초대량주문'
WHEN Quantity BETWEEN 20 AND 45 THEN '대량주문'
ELSE '일반주문'
END
FROM OrderDetails;
형식 |
설명 |
IFNULL(A,B) |
A가 NULL일 시 B출력 |
SELECT
IFNULL('A', 'B'), -- A
IFNULL(NULL, 'B'); -- B