마당서점 데이터베이스를 이용한 SQL 기초 쿼리 연습
| bookid | bookname | publisher | price |
|---|---|---|---|
| 1 | 축구의 역사 | 굿스포츠 | 7000 |
| 2 | 축구 아는 여자 | 나무수 | 13000 |
| 3 | 축구의 이해 | 대한미디어 | 22000 |
| 4 | 골프 바이블 | 대한미디어 | 35000 |
| 5 | 피겨 교본 | 굿스포츠 | 8000 |
| 6 | 배구 단계별기술 | 굿스포츠 | 6000 |
| 7 | 야구의 추억 | 이상미디어 | 20000 |
| 8 | 야구를 부탁해 | 이상미디어 | 13000 |
| 9 | 올림픽 이야기 | 삼성당 | 7500 |
| 10 | Olympic Champions | Pearson | 13000 |
| orderid | custid | bookid | saleprice | orderdate |
|---|---|---|---|---|
| 1 | 1 | 1 | 6000 | 2024-07-01 |
| 2 | 1 | 3 | 21000 | 2024-07-03 |
| 3 | 2 | 5 | 8000 | 2024-07-03 |
| 4 | 3 | 6 | 6000 | 2024-07-04 |
| 5 | 4 | 7 | 20000 | 2024-07-05 |
| 6 | 1 | 2 | 12000 | 2024-07-07 |
| 7 | 4 | 8 | 13000 | 2024-07-07 |
| 8 | 3 | 10 | 12000 | 2024-07-08 |
| 9 | 2 | 10 | 7000 | 2024-07-09 |
| 10 | 3 | 8 | 13000 | 2024-07-10 |
| custid | name | address | phone |
|---|---|---|---|
| 1 | 박지성 | 영국 맨체스타 | 000-5000-0001 |
| 2 | 김연아 | 대한민국 서울 | 000-6000-0001 |
| 3 | 김연경 | 대한민국 경기도 | 000-7000-0001 |
| 4 | 추신수 | 미국 클리블랜드 | 000-8000-0001 |
| 5 | 박세리 | 대한민국 대전 | NULL |
SELECT bookname FROM book
WHERE bookid = 1;
SELECT bookname FROM book
WHERE price >= 20000;
SELECT SUM(saleprice) FROM orders
WHERE custid = 1;
박지성의 custid를 모를 경우 서브쿼리 사용
SELECT SUM(saleprice) FROM orders WHERE custid = (SELECT custid FROM customer WHERE name = '박지성');
SELECT COUNT(*) FROM orders
WHERE custid = 1;
SELECT COUNT(DISTINCT b.publisher)
FROM orders o JOIN book b ON o.bookid = b.bookid
WHERE o.custid IN (SELECT custid FROM customer WHERE name = '박지성');
=vsIN차이
=: 서브쿼리 결과가 1개일 때만 사용 가능, 2개 이상이면 오류IN: 결과가 여러 개여도 정상 작동 → 동명이인 등을 고려하면IN이 더 안전
SELECT b.bookname, b.price, o.saleprice, (b.price - o.saleprice) AS difference
FROM orders o JOIN book b ON o.bookid = b.bookid
WHERE o.custid IN (SELECT custid FROM customer WHERE name = '박지성');
| bookname | price | saleprice | difference |
|---|---|---|---|
| 축구의 역사 | 7000 | 6000 | 1000 |
| 축구의 이해 | 22000 | 21000 | 1000 |
| 축구 아는 여자 | 13000 | 12000 | 1000 |
SELECT bookname
FROM book
WHERE bookid NOT IN (
SELECT bookid FROM orders
WHERE custid IN (SELECT custid FROM customer WHERE name = '박지성')
);
⚠️ 주의:
FROM orders JOIN book으로 시작하면 안 됨
- "박지성이 구매하지 않은 도서" → 기준이 전체 도서(book)
FROM book에서 시작해서 박지성의 주문 목록을NOT IN으로 제외해야 함FROM orders로 시작하면 "다른 사람들이 주문한 책"이 나와버려 결과가 틀림
SELECT COUNT(*) FROM book;
SELECT COUNT(DISTINCT publisher) FROM book;
DISTINCT없이 쓰면 중복 출판사가 여러 번 카운트됨
SELECT name, address FROM customer;
SELECT orderid FROM orders
WHERE orderdate BETWEEN '2024-07-04' AND '2024-07-07';
⚠️
IN ('2024-07-04', '2024-07-07')은 4일과 7일만 조회됨, 사이 날짜 누락
SELECT orderid FROM orders
WHERE orderdate NOT BETWEEN '2024-07-04' AND '2024-07-07';
SELECT name, address FROM customer
WHERE name LIKE '김%';
SELECT name, address FROM customer
WHERE name LIKE '김%아';
⚠️
'김_아'는 이름이 3글자(김X아)인 경우만 해당됨
_: 딱 1글자만 대체%: 0글자 이상 대체 → 4글자 이상 이름도 포함
SELECT name FROM customer
WHERE custid NOT IN (SELECT custid FROM orders);
SELECT SUM(saleprice) AS 총액, AVG(saleprice) AS 평균금액
FROM orders;
SELECT c.name, SUM(o.saleprice) AS 구매액
FROM customer c JOIN orders o ON c.custid = o.custid
GROUP BY c.custid, c.name;
"고객별" 이라는 단어가 나오면
GROUP BY사용
GROUP BY c.custid, c.name으로 쓰는 이유: 동명이인이 있을 경우 이름만으로 묶으면 합산될 수 있어서 custid를 함께 명시하는 것이 안전
SELECT c.name, b.bookname
FROM customer c
JOIN orders o ON c.custid = o.custid
JOIN book b ON o.bookid = b.bookid;
customer와 book은 직접 연결되는 컬럼이 없음
orders가 중간 테이블 역할 → JOIN을 두 번 해야 함customer --- orders --- book custid custid bookid bookid
SELECT b.bookname, b.price, o.saleprice, (b.price - o.saleprice) AS difference
FROM book b JOIN orders o ON b.bookid = o.bookid
WHERE (b.price - o.saleprice) = (
SELECT MAX(b.price - o.saleprice)
FROM book b JOIN orders o ON b.bookid = o.bookid
);
MAX()만 쓰면 최댓값 숫자만 나옴
해당 주문 정보 전체를 가져오려면 서브쿼리로 최댓값을 구한 뒤WHERE로 해당 행을 찾아야 함
SELECT c.name
FROM customer c JOIN orders o ON c.custid = o.custid
GROUP BY c.custid, c.name
HAVING AVG(o.saleprice) > (SELECT AVG(saleprice) FROM orders);
WHEREvsHAVING
구분 사용 위치 일반 조건 WHERE집계함수 조건 HAVING
HAVING은 항상GROUP BY뒤에 위치
| 질문 패턴 | 기준 테이블 |
|---|---|
| "~한 것들 중에서 집계" | 행위 테이블 (orders) |
| "전체 중에서 ~한/안한 것" | 대상 테이블 (book, customer) |
핵심: "무엇을" 조회하는지가 FROM/기준 테이블을 결정한다
| 패턴 | 의미 |
|---|---|
% | 0글자 이상 임의의 문자 |
_ | 정확히 1글자 |
COUNT(*) : NULL 포함 전체 행 수COUNT(컬럼) : NULL 제외 행 수COUNT(DISTINCT 컬럼) : 중복 제외 고유값 수HAVING 사용-- 단일 결과 → = 사용 가능
WHERE custid = (SELECT custid FROM customer WHERE name = '박지성')
-- 복수 결과 가능성 → IN 사용 권장
WHERE custid IN (SELECT custid FROM customer WHERE name = '박지성')