[ 5주차 - 0910 ]
금일 커리큘럼
├ 09:00 ~ 12:00 관계형 데이터베이스 (SQL 설명, SELECT, WHERE, LIKE, NULL, LIMIT)
└ 13:00 ~ 18:00 관계형 데이터베이스 (SQL 함수, ORDER BY, GROUP BY, HAVING, JOIN)
1. SQL
SQL(Structured Query Language)은 관계형 데이터베이스를 조작하기 위한 표준 언어
SQL 문법 특징
- 대부분의 SQL 명령은 세미콜론(;)으로 끝남
- 키워드는 대소문자를 구분하지 않음
- 데이터는 대소문자를 구분
-- 예시
SELECT 컬럼명,컬럼명 FORM 테이블명,테이블명;
-- DBMS 함수 실행
SELECT version();
-- 수식계산
SELECT 10 * 2.5;
SELECT sin(pi()/4), (4+1)*5;
-- 여러줄
SELECT
user(),
current_date;
2. SELECT 문
기본형태
SELECT [DISTINCT] 컬럼명 [AS 별칭]
FROM 테이블명
WHERE 조건
ORDER BY 컬럼 [ASC|DESC];
DESC 테이블명; -- 스키마 설정 확인
- ORDER BY : 기준컬럼
- ASC 오름차순, DESC 내림차순
DESC 테이블명;같은 경우 스키마 설정 확인임. (정수,null 등)
데이터 조회
-- 전체 조회
SELECT * FROM emp;
-- 특정 컬럼 조회
SELECT job FROM emp;
-- 특정 컬럼 중복값 제외 조회
SELECT DISTINCT job FROM emp;
SELECT DISTINCT job, empno FROM emp;
-- 컬럼 별칭 부여 방식
SELECT empno 사번,
ename AS "사원 이름",
mgr AS 매니저
FROM emp;
컬럼 결합과 연산
-- 문자열 결합
SELECT concat(ename, ' [', job, ']') AS "이름 [직원]" FROM emp;
-- 산술 연산
SELECT
ename,
sal,
sal / 12 AS "월급"
FROM emp;
중복 제거
-- 중복된 값 제거
SELECT DISTINCT department_id
FROM employees;
-- 여러 컬럼의 조합으로 중복 제거
SELECT DISTINCT department_id, job_id
FROM employees;
3. WHERE 문과 조건 검색
WHERE 심플 예시
SELECT * FROM emp WHERE deptno = 10;
SELECT * FROM emp WHERE job = 'manager';
SELECT * FROM emp WHERE sal > 2500;
SELECT * FROM emp WHERE sal > 2500 and job = 'manager';
SELECT * FROM emp
WHERE (deptno = 10 or deptno = 20)
and sal >= 2000;
논리연산
- and연산은 or보다 우선순위 (먼저필터)
-- and 연산
SELECT * FROM emp
WHERE sal >= 1000 and deptno = 10;
-- or 연산
SELECT * FROM emp
WHERE deptno = 10 or deptno = 20;
-- not 연산
SELECT * FROM emp
WHERE not deptno = 30;
-- and or 우선순위 확인
SELECT * FROM emp
WHERE deptno = 10 or deptno = 20
and sal >= 2000;
-- deptno 10, 20 중 2000 이상인 것만 추출 목적이였으나,
-- 결과는 dept 10 전부 나오고, 20에서 2000이상만 나옴
-- 원하는 결과 나올려면
-- (deptno = 10 or deptno = 20) and sal >= 2000;
in 연산
-- IN 사용
SELECT * FROM emp
WHERE deptno in (10, 20); -- 10, 20 인 것
-- NOT IN 사용
SELECT * FROM emp
WHERE deptno not in (20, 30); -- 20, 30 아닌 것
between 연산
-- 일반 범위
SELECT * FROM emp
WHERE sal BETWEEN 2300 and 3000; -- 2300이상 3000이하
-- 날짜 범위
SELECT * FROM emp
WHERE hiredate BETWEEN '1981-01-01' and '1981-12-31';
4. 패턴 매칭 - LIKE
와일드카드 문자형태
%: 0개 이상의 문자_: 정확히 1개의 문자
!! 포맷형식 아님
LIKE 사용 방식
-- 이름이 F로 시작
SELECT * FROM emp
WHERE ename like 'F%';
-- 이름이 두번째 O
SELECT * FROM emp
WHERE ename like '_O%';
-- 1981년 입사
SELECT * FROM emp
WHERE hiredate like '1981%';
-- 함수형 방식
SELECT * FROM emp
WHERE year(hiredate) = 1981;
-- 9월 입사
SELECT * FROM emp
WHERE hiredate like '____-09%'; -- '_' 4개
-- 함수형 방식
SELECT * FROM emp
WHERE month(hiredate) = 9;
5. NULL 처리
null 확인 방법
NULL은 = 또는 != 연산자로 비교할 수 없음. 함수로 써야함
-- null 인 경우
SELECT * FROM emp
WHERE comm is NULL;
-- null 아닌 경우
SELECT * FROM emp
WHERE comm is not NULL;
null 처리 함수 (ifnull, coalesce)
-- ifnull : null인 경우 대체 처리
SELECT comm, ifnull(comm, -1) -- null를 -1로 대체
FROM emp;
SELECT ename, sal, comm,
sal + ifnull(comm, 0) as 상여금포함연봉
FROM emp;
-- sal 연봉 | comm 상여금 (null있음)
SELECT ename, comm, job,
coalesce(comm, job, '하하')
FROM emp;
-- comm 이 null이면 job을 쓰고,
-- job도 null이면 '하하'
6. 정렬 - ORDER BY
- FROM 구절에 붙음
단일 컬럼 정렬
-- 오름차순 asc
SELECT * FROM emp
ORDER BY ename asc;
-- 내림차순 desc
SELECT * FROM emp
ORDER BY ename desc;
다중 컬럼
SELECT deptno, ename, sal FROM emp
ORDER BY deptno, sal asc;
-- 부서번호, 연봉 오름차순
SELECT deptno, ename, sal FROM emp
ORDER BY deptno asc, sal desc;
-- 부서번호 오름차순, 연봉 내림차순
SELECT empno, mgr*22 as 월급, ename FROM emp
ORDER BY 월급 desc, ename asc;
-- 별칭기준 내림차순, 이름 오름차순
7. 제한걸기 - LIMIT
SELECT * FROM emp
ORDER BY ename asc
LIMIT 5; -- 5개까지만 노출
-- 페이징 LIMIT (페이지번호-1) * 페이지크기, 페이지크기
SELECT deptno, job, ename, sal
FROM emp
ORDER BY deptno asc
LIMIT 0, 5; -- 1 페이지
SELECT deptno, job, ename, sal
FROM emp
ORDER BY deptno asc
LIMIT 5, 5; -- 2 페이지
8. SQL 함수
문자열
-- 대소문자
SELECT upper('hello'), lower('WORLD'); -- HELLO | world
-- 문자열 결합
SELECT concat('Hello', ' ', 'World'); -- Hello World
-- 부분 문자열
SELECT substring('Hello World', 1, 5); -- Hello
SELECT substr('Hello World', 1, 5); -- Hello
-- 문자열 길이
SELECT length('Hello World'); -- 11
-- 공백 제거
SELECT trim(' 양쪽 공백 '),
ltrim(' 좌측 공백'),
rtrim('우측 공백 ');
-- 문자열 치환
SELECT REPLACE('Hello World', 'World', 'MySQL'); -- Hello MySQL
-- 패딩
SELECT lpad('test', 5, '*'), -- *test
rpad('test', 7, '?'); -- tset???
날짜
-- 현재날짜, 시간 등
SELECT curdate(), curtime(), now();
-- yyyy-mm-dd | hh:mm:ss | yyyy-mm-dd hh:mm:ss
-- 년월일 포맷팅
SELECT date_format(now(), '%y년 %m월 %d일');
-- 오늘 날짜와 시간
SELECT curdate() as 금일날짜, curtime() as 현재시간;
-- date_format : 몇년, 몇월, 몇일
SELECT
date_format(curdate(), '%Y년') as 년도, -- 2025년
date_format(curdate(), '%m월') as 월, -- 09일
date_format(curdate(), '%d일') as 일; -- 10일
-- 날짜연산 : date_add, date_sub
SELECT
curdate() as 오늘날짜,
date_add(curdate(), interval 200 day) as '200일 후',
date_sub(curdate(), interval 100 day) as '100일 전';
-- 2025-09-10 | 2026-03-29 | 2025-06-02
-- 날짜차이 : datediff (일), timestampdiff(기준)
SELECT
curdate() as 오늘날짜,
abs(datediff('2024-01-01', now())) as '일차이',
abs(timestampdiff(month, '2024-01-01', curdate())) as '월차이',
abs(timestampdiff(year, '2024-01-01', curdate())) as '년도차이';
-- 618 | 20 | 1
활용 예시
-- 활용
SELECT
deptno as 부서번호,
empno as 사번,
ifnull(mgr, 7839) as 책임자,
job as 직급,
concat(ename, '님') as 사원명,
hiredate as 입사일,
concat(
abs(timestampdiff(year, hiredate, curdate())),
"년"
) as 년차,
concat(floor(sal), '만원') as 연봉,
concat(floor(ifnull(comm, 0)), '만원') as 상여금
FROM emp
ORDER BY deptno asc;
9. 그룹 함수
-- count: 행 개수
SELECT count(*) FROM emp; -- 전체 행 개수 : 14
SELECT count(comm) FROM emp; -- NULL 제외 행 개수
-- sum: 합계
SELECT sum(sal) as 총인건비 FROM emp;
-- 29025.00
-- avg: 평균
SELECT avg(sal) as 평균인건비 FROM emp;
-- 2073.214286
-- max, min: 최대값, 최소값
SELECT max(sal) as 최고연봉액,
min(sal) as 최저연금액 FROM emp;
-- 5000.00 | 800.00
group by
- group by 컬럼 : 해당 컬럼의 값이 같은 행들을 하나의 그룹으로 묶음
- FROM 이후 구절에 붙음
-- 직급별 평균연봉액
SELECT job, avg(sal) FROM emp
GROUP BY job;
-- 부서 내 직급별 평균연봉액
SELECT deptno, job, avg(sal) FROM emp
GROUP BY deptno, job
ORDER BY 1, 2; -- 첫째,두번째열 (deptno,job) 오름차순
having
- where : 행(row) 단위 조건 (그룹핑 전)
- 데이터를 필터링한 후 그룹을 만듬
- having : 그룹(group) 단위 조건 (그룹핑 후)
- 그룹을 만든 뒤, 집계 결과를 조건으로 걸러냄
- group by 이후 구절에 붙음
-- 10번 부서 제외 모든 사원의 부서별, 직급별 평균 연봉액
-- 단 평균 1000이상
SELECT deptno, job, avg(sal) as 평균연봉액 FROM emp
WHERE deptno != 10
GROUP BY deptno, job
HAVING avg(sal) >= 1000;
10. JOIN
JOIN은 하나 이상 테이블로부터 연관 데이터 검색하는 방식
- Cross Join
- 두 테이블의 모든 가능한 쌍이 나타남 (Cartesian Product, 데카르트 곱)
- 조건이 없으면 행 개수 = A행 × B행 → 데이터 폭발 가능
- 단점: 실제로는 잘 안 쓰이며, 실수로 사용하면 성능 저하와 불필요한 대량 결과 발생
- Inner Join
- 조인 조건을 만족하는 튜플(행)만 나타남
- 가장 많이 사용하는 일반적인 조인 방식
- Outer Join
- 조인 조건을 만족하지 않는 튜플도 NULL과 함께 나타남
- 종류: LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN
- Self Join
- 자기 자신과 조인
- 같은 테이블을 두 번 별칭(alias) 주어 사용
- 예: 직원 테이블에서 직원과 상사를 매칭할 때
연습 db 스키마 훑어보기
CREATE TABLE dept ( -- 부서 테이블
deptno int NOT NULL AUTO_INCREMENT,
dname varchar(20),
loc varchar(20),
CONSTRAINT pk_dept PRIMARY KEY ( deptno )
) engine=InnoDB;
CREATE TABLE emp ( -- 직원 테이블
empno int NOT NULL AUTO_INCREMENT,
ename varchar(20),
job varchar(20),
mgr smallint,
hiredate date,
sal numeric(7,2),
comm numeric(7,2),
deptno int,
CONSTRAINT pk_emp PRIMARY KEY ( empno )
) engine=InnoDB;
DEPT -- 부서 테이블
+-----------+-----------------------+
| deptno | int PK AUTO_INCREMENT |
| dname | varchar(20) |
| loc | varchar(20) |
+-----------+-----------------------+
PK: pk_dept(deptno)
EMP -- 직원 테이블
+-----------+-----------------------+
| empno | int PK AUTO_INCREMENT |
| ename | varchar(20) |
| job | varchar(20) |
| mgr | smallint | # 상사 empno (자기참조)
| hiredate | date |
| sal | numeric(7,2) |
| comm | numeric(7,2) |
| deptno | int | # FK → dept.deptno
+-----------+-----------------------+
PK: pk_emp(empno)
FK: fk_emp_dept (deptno → dept.deptno)
INDEX: idx_emp (deptno)
- 기본키 (Primary Key, PK)
- 각 테이블의 행을 유일하게 식별
dept.deptno,emp.empno
- 외래키 (Foreign Key, FK)
- 다른 테이블의 PK(또는 Unique)를 참조
emp.deptno → dept.deptno
크로스조인과 이너조인 차이
/* 크로스 조인 | 권장하지 않음 -------- */
-- 모든 가능한 조합
SELECT ename, sal, dname FROM emp, dept;
SELECT e.ename, e.sal, d.deptno, d.dname FROM emp e, dept d;
-- -> 해당 결과 = emp 행수 × dept 행수 만큼 쌍이 생김
/* 이너 조인 | 추천함 -------- */
-- 두 테이블에서 deptno가 일치하는 데이터만
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno; -- 만족하는 경우만
이너조인 방식
/* 심플 조인 -------- */
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno;
/* ANSI 조인 -------- */
-- natural join (자동으로 같은 컬럼 기준 조인)
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e NATURAL join dept d;
-- join ~ using (동일한 컬럼명일 때)
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e join dept d USING(deptno);
-- join ~ on
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e join dept d ON e.deptno = d.deptno;
조인 추가 조건
-- 심플조인은 where 절 이미 써있으니 and 추가 사용
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno
and e.deptno = 20;
-- ansi 조인은 where 절 추가 사용
SELECT e.ename, e.sal, d.deptno, d.dname
FROM emp e NATURAL join dept d
WHERE e.deptno = 20;
etc.
hr DB 관련 연습풀이
-- 1. 모든 직원 이름 , 이메일
SELECT concat(first_name, ' ', last_name) as '이름+성',
email as 이메일
FROM employees;
-- 2. 급여 1500 이상 직원
SELECT * FROM employees
WHERE salary >= 1500 is not NULL;
-- 3. 2005년에 입사한 직원
SELECT * FROM employees
WHERE year(hire_date) = 2005;
-- 4. 이름 an 직원
SELECT * FROM employees
WHERE first_name LIKE '%an%' or last_name LIKE '%an%';
-- 5 이메일 S 시작, 급여 내림차순
SELECT * FROM employees
WHERE email LIKE 'S%'
ORDER BY salary desc;
-- 6. 부서별 직원 수, 평균급여
SELECT
department_id as 부서번호,
COUNT(*) as '부서별 직원 수',
avg(salary) as 평균급여
FROM employees
GROUP BY department_id;
-- 7. 직원이 5명 이상 부서
SELECT
department_id as 부서번호,
COUNT(department_id) as '부서별 직원 수'
FROM employees
GROUP BY department_id
HAVING COUNT(*) >= 5;
'멋사 - 부트캠프 19기 : Java > DataBase' 카테고리의 다른 글
| (09.12) 데이터베이스 - TABLE DML, INDEX, DB 설계, 트랜잭션, ALTER, JDBC (0) | 2025.09.12 |
|---|---|
| (09.11) 데이터베이스 - JOIN 심화, 상관 서브쿼리, 집합 연산, 윈도우 함수, DDL과 DB설계 (0) | 2025.09.11 |
| (09.09) 데이터베이스 - DB 개념, RDB와 MySQL, Docker, MySQL Workbench, SQL 문법 (0) | 2025.09.09 |