MySQL 기초, SELECT 문, 내장 함수
데이터(Data) : 현실 세계에서 관찰하고 측정한 사실의 값 (원재료)
정보(Information): 데이터를 처리/가공해서 의사결정에 활용 가능한 형태
지식(Knowledge) : 정보를 바탕으로 추론하고 일반화한 규칙
예: 온도 35°C(데이터) → "오늘 폭염이다"(정보) → "여름엔 냉방 수요가 늘어난다"(지식)
데이터베이스(DB): 조직의 데이터를 통합해서 저장한 운영 데이터의 집합
DBMS(Database Management System): DB를 관리하는 소프트웨어. MySQL, Oracle, PostgreSQL 등
File System vs DBMS:
| File System | DBMS | |
|---|---|---|
| 데이터 중복 | 많음 (파일마다 중복) | 최소화 |
| 데이터 공유 | 어려움 | 동시 공유 가능 |
| 일관성 | 깨지기 쉬움 | 트랜잭션으로 보장 |
| 보안 | 파일 단위 | 사용자/권한 단위 |
UTF-8: 영문 1바이트, 한글 3바이트. 웹에서 표준으로 사용.
UTF-16: 모든 문자를 2바이트(또는 4바이트)로 표현. 파일 크기가 커질 수 있음.
DB 설계 시 한글을 저장해야 하면 charset을 utf8mb4로 설정하는 게 표준이다. (utf8mb4는 이모지 포함 4바이트 문자도 지원)
DBA(Database Administrator): DB 전체를 관리하는 관리자. 계정 생성, 권한 부여, 백업/복구 담당.
-- DBA가 하는 작업 예시
create database madangdb;
create user madang@localhost identified by 'madang';
grant all privileges on madangdb.* to madang@localhost;
| 분류 | 이름 | 명령어 | 설명 |
|---|---|---|---|
| DDL | Data Definition Language | CREATE, ALTER, DROP | 테이블 구조 정의 |
| DML | Data Manipulation Language | SELECT, INSERT, UPDATE, DELETE | 데이터 조작 |
| DCL | Data Control Language | GRANT, REVOKE | 권한 관리 |
SELECT [DISTINCT] * | 컬럼명 [AS alias] | 연산 | 함수
FROM 테이블명
[WHERE 조건]
[GROUP BY 컬럼명 [HAVING 조건]]
[ORDER BY 컬럼명 [ASC|DESC]]
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
작성은 SELECT부터 하지만, 실제 실행은 FROM(테이블)부터 시작한다.
-- 기본 조회
SELECT * FROM goods;
-- 별칭(alias) 사용
SELECT brand, price, price * 1.1 AS "인상된 가격"
FROM goods;
-- 중복 제거
SELECT DISTINCT cno FROM goods;
-- = , != , <> , > , >= , < , <=
SELECT * FROM goods WHERE price >= 5000;
SELECT * FROM members WHERE id != 'kdg';
-- NULL은 = 로 비교할 수 없다
SELECT * FROM goods WHERE cno = null; -- 안 됨
SELECT * FROM goods WHERE cno IS NULL; -- O
SELECT * FROM goods WHERE cno IS NOT NULL; -- O
-- 작은값 이상 큰값 이하 (양 끝 포함)
SELECT * FROM goods WHERE price BETWEEN 5000 AND 15000;
-- 큰값 AND 작은값으로 쓰면 조회 안 됨
-- 하나라도 일치하면 조회
SELECT * FROM goods WHERE cno IN (10, 20);
-- 모두 일치하지 않을 때
SELECT * FROM goods WHERE cno NOT IN (10, 20);
SELECT * FROM goods WHERE maker NOT IN ('LG', '롯데');
-- _ : 한 문자 대체
-- % : 길이 상관 없음
SELECT * FROM goods WHERE maker LIKE '%LG%'; -- LG 포함
SELECT * FROM book WHERE bookname LIKE '_구%'; -- 두 번째 글자가 '구'
SELECT * FROM book WHERE bookname LIKE '%축구%'; -- '축구' 포함
-- 주의: 와일드카드 없이 LIKE를 쓰면 = 과 같은 효과
-- 성능은 = 가 더 좋으므로 정확한 값 비교는 = 사용
-- 조건에 따라 다른 값을 반환
SELECT bookname, price,
CASE
WHEN price < 10000 THEN price * 1.15
ELSE price * 1.1
END AS "인상 후 가격"
FROM book;
-- 값 매핑
SELECT gno, brand, price,
CASE cno
WHEN '10' THEN '음식'
WHEN '20' THEN '전자제품'
WHEN '30' THEN '책'
WHEN '40' THEN '가구'
ELSE '미분류'
END AS 분류명
FROM goods;
-- 오름차순 (기본)
SELECT * FROM goods ORDER BY price;
SELECT * FROM goods ORDER BY price ASC;
-- 내림차순
SELECT * FROM goods ORDER BY price DESC;
-- 복합 정렬: 분류번호 내림차순, 같은 분류 내에서 이름 오름차순
SELECT * FROM goods ORDER BY cno DESC, brand ASC;
-- NULL을 제외하고 연산
SELECT COUNT(*), -- 전체 행 수 (NULL 포함)
COUNT(cno), -- cno가 NULL이 아닌 행 수
SUM(price),
AVG(price),
MAX(price),
MIN(price)
FROM goods;
-- DISTINCT와 함께
SELECT AVG(ALL price), AVG(DISTINCT price) FROM book;
SELECT ABS(-78); -- 절대값: 78
SELECT FLOOR(3.9); -- 버림: 3
SELECT CEIL(3.1); -- 올림: 4
SELECT ROUND(4.875, 1); -- 반올림(소수 1자리): 4.9
-- 연결
SELECT CONCAT('마당', ' 서점', '유레카');
-- 추출
SELECT LEFT(brand, 2), RIGHT(brand, 2) FROM goods;
SELECT SUBSTRING(brand, 1, 3) FROM goods; -- 1번째부터 3글자
-- 문자 수 vs 바이트 수
SELECT CHAR_LENGTH('데이터'), -- 3 (문자 수)
LENGTH('데이터'); -- 9 (바이트 수, 한글 3바이트 × 3)
-- 치환
SELECT REPLACE(bookname, '야구', '농구') FROM book;
-- 대소문자
SELECT UPPER('hello'), LOWER('WORLD');
-- 공백 제거
SELECT TRIM(' hello ');
SELECT LTRIM(' hello'), RTRIM('hello ');
-- 반복
SELECT REPEAT('hello ', 5);
-- NULL이면 대체값 사용
SELECT IFNULL(cno, '미분류') FROM goods;
SELECT IFNULL(phone, '연락처 없음') FROM customer;
-- IF 함수
SELECT IF(price >= 10000, '고가', '저가') FROM goods;
-- 현재 날짜/시간
SELECT CURDATE(), CURTIME(), NOW(), SYSDATE();
-- 날짜 연산
SELECT DATE_ADD(SYSDATE(), INTERVAL 10 DAY); -- 10일 후
SELECT DATE_SUB(SYSDATE(), INTERVAL 1 MONTH); -- 1개월 전
-- 날짜 부분 추출
SELECT YEAR(NOW()), MONTH(NOW()), DAYOFMONTH(NOW());
SELECT HOUR(NOW()), MINUTE(NOW()), SECOND(NOW());
-- 요일
SELECT DAYOFWEEK(SYSDATE()); -- 일(1) ~ 토(7)
SELECT DAYNAME(SYSDATE()); -- 'Monday' 등
-- 포맷
SELECT DATE_FORMAT(SYSDATE(), '%Y년 %m월 %d일 %H시 %i분');
-- 이번 달 주문 조회 (인덱스 타는 방식)
SELECT * FROM orders
WHERE odate >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
AND odate < DATE_FORMAT(CURDATE() + INTERVAL 1 MONTH, '%Y-%m-01');
MONTH(odate) = MONTH(NOW())처럼 컬럼에 함수를 적용하면 인덱스를 못 탄다. 범위 비교로 쓰는 게 성능에 좋다.
-- 설정 확인
SHOW VARIABLES WHERE variable_name LIKE '%low%';
-- lower_case_table_names
-- 1: 대소문자 구별 안 함 (Windows 기본)
-- 0: 대소문자 구별 함 (Linux, Mac 기본)
날짜 조회에서 MONTH(odate) = MONTH(NOW())와 범위 비교 방식의 차이가 인상 깊었다. 컬럼에 함수를 씌우면 인덱스를 사용할 수 없다는 건 Java에서 HashMap을 쓸 때 hashCode()가 중요한 것과 같은 원리다. 어떻게 저장됐는지를 알아야 빠르게 찾을 수 있다.
알고리즘에서 시간복잡도를 따지던 습관이 SQL에서도 그대로 이어진다. SELECT * 대신 필요한 컬럼만, 인덱스를 탈 수 있는 조건식을 쓰는 것이 중요하다.
데이터 정보 지식 DBMS File System vs DB UTF-8 utf8mb4 DBA DDL DML DCL SELECT 실행 순서 FROM-WHERE-GROUPBY-HAVING-SELECT-ORDERBY DISTINCT IS NULL IS NOT NULL BETWEEN IN NOT IN LIKE % _ CASE WHEN ELSE END ORDER BY ASC DESC 집계함수 COUNT SUM AVG MAX MIN CHAR_LENGTH vs LENGTH IFNULL DATE_FORMAT DATE_ADD DATE_SUB