DB, DBMS
● 데이터(DIKW): 자료(Data) -> 정보(Information) -> 지식(Knowledge) -> 지혜 (Wisdom)
● DB 개념
○ 자료를 효율적으로 관리하기 위해서 데이터들 사이에 관계를 맺어둔 파일
○ 상호 연관 있는 데이터들의 체계적인 집합
○ 어느 조직에서 다수의 프로그램들이 공통으로 사용하기 위해 통합 저장된 데이터의 집합
○ DB 자체가 정보를 제공X, 이를 활용해 정보를 찾는 것이 데이터 마이닝
● DB 특징
○ 자료 추상: 복잡한 자료 쉽게 사용, 개념화, 사물의 공통 성질 추출
○ 자료 독립: 자료와 프로그램의 독립성 유지
○ 자기정의: 자료의 구성과 내용을 DB 자신이 저장 및 관리
● DB 장점
○ 데이터의 논리적 독립성: 논리적 구조가 변경되어도 DB를 이용하는 프로그램에는 영향 X
○ 데이터의 물리적 독립성: 저장 장치의 구조를 변경해도 DB를 이용하는 프로그램 및 개념 스키마에는 영향 X
○ 데이터의 무결성 유지: 데이터를 사용할 때 다양한 제약조건을 데이터에 결점이 생기지 않도록 유지
○ 데이터 중복성 최소화: 데이터를 통합해 구성함으로 중복을 미리 통제
○ 데이터 불일치 제거: 중복을 최소화해 불일치를 제거
● DB 발전 과정: 파일 시스템 -> 계층형-> 망형 -> [관계형]-> 객체형 -> 객체관계형
● 관계형 데이터베이스 종류: Oracle / My-SQL / SQL Server / MariaDB
● 데이터 처리 시스템의 형태
○ 일괄처리 시스템: 시스템의 효율성을 최대한 높이기 위해 일정 시간 또는 일정량의 데이터를 모아서 한번에 처리하는 시스템
○ 온라인처리 시스템: 데이터 발생 즉시, 또는 데이터 처리 요구가 있는 즉시 처리해 결과를 산출하도록 하는 방식
○ 분산처리 시스템: 지리적으로 분산된 여러대의 컴퓨터를 통신 회선으로 연결해 논리적으로 하나의 시스템을 사용하는 것처럼 운영하는 방식
● DBMS 개념
○ 응용 프로그램과 DB의 중재자, 모든 프로그램들이 DB를 공유 할 수 잇또록 관리해 주는 소프트웨어
○ 응용 프로그램과 데이터 간에 상호 의존 관계 문제를 해결, 중복을 최소화해 데이터의 불일치 제거
○ 프로그램(클라이언트)이 DB(서버)를 이용해 데이터에 접근
● DBMS 필수 기능
○ 정의 기능: 데이터의 형태, 구조, 데이터를 저장하는 것에 관한 내용 정의
○ 조작 기능: 사용자의 요구에 따라 데이터의 검색, 갱신, 삽입, 삭제 등을 지원
○ 제어 기능: 데이터의 정확성, 안전성을 유지하는 기능
● DB 스키마 개념
○ DB의 구조(개체, 속성, 관계)에 대한 정의 및 제약 조건 등을 기술한 것
○ 내부 스키마: 데이터 구조의 형식을 구체적으로 정의 / 외부 단계, 각 사용자 관점
○ 개념 스키마: 데이터 전체의 구조를 정의 / 개념 단계, 모든 사용자 관점
○ 외부 스키마: 실제로 이용자가 취급하는 데이터 구조를 정의 / 내부 단게, 물리적인 접근 방법
○ MYSQL = 스키마 = DB Oracle = 다수 스키마
DB 설계
● 데이터 모델링
○ 개념: 현실세계의 다양한 데이터를 DB에 표현하기 위한 중간 과정 / 데이터의 크기 및 유형을 결정해 DB에 사용할 수 있도록 데이터를 정형화
○ 순서: 개념적 구조 -> 논리적 구조 -> 물리적 구조
● DB 설계 과정
○ 요구 분석 -> 개념적 설계 -> 논리적 설계 -> 물리적 설계 -> 구현
○ 요구 분석
- DB를 사용할 주요 사용자를 결정 / 사용자가 조직에서 수행하는 업무를 분석 / 다양한 조사 방법을 통해 요구 사항 파악
- 결과물: 파악한 요구 사항에 대한 분석 결과를 요구 사항 명세서로 작성
○ 개념적 설계
- 데이터를 구조화, 정형화시키기 위해 추상적인 개념으로 표현하는 과정 / 개념적 스키마를 설계하는 단계
- 결과물: E-R 다이어그램
○ 논리적 설계
- 개념적 스키마를 관계형 DB인 경우 테이블과 같은 논리적 데이터 모델을 이용해 논리적 구조로 표현, 정규화 수행, DBMS에 종속적
- 결과물: 릴레이션 스키마, 데이터 타입, 길이, 널 값 허용 여부, 기본 값, 제약조건 등을 세부적으로 결정
○ 물리적 설계
- HW, OS의 특성을 고려해 필요한 인덱스 구조나 내부 저장 구조 등에 대한 물리적 구조를 설계 / DBMS, HW에 종속적
- 결과물: 물리적 스키마
○ 구현
- SQL을 사용해 DBMS를 통해 실제 DB를 만드는 과정
- 결과물: DB
ERD - E-R모델
● E-R 모델
○ 개념: 피터 첸이 제안한 개념적 데이터 모델 / 현실 세계를 개체와 개체 간의 관계를 이용해 개념적 구조로 표현
○ ERD 구성요소
● 개체
○ 데이터로써 DB에 저장할 가치가 있는 중요한 사람이나 사물, 개념, 사건
○ 개체는 다른 개체와 구별되는 이름을 갖고, 각 개체는 고유한 특성이나 상태를 나타내는 속성을 하나 이상 가짐
● 속성
○ 개념: 개체나 관계가 가지고 있는 고유의 특성 / DB에 저장하는 데이터의 가장 작은 논리적 단위
○ 유형
- 단일 값 속성: 값을 하나만 가질수 있는 속성
- 다중 값 속성: 값을 여러 개 가질수 있는 속성
- 단순 속성: 의미를 더는 분해할 수 없는 속성
- 복합 속성: 의미를 분해할 수 있는 속성
- 유도 속성: 기존의 다른 속성의 값에서 유도되어 결정되는 속성
- 널 속성: 아직 결정되지 않았거나 존재하지 않는 값, 공백, 0과는 다름
- 키 속성: 각 개체를 식별하는데 사용되는 속성, 둘 이상의 속성들로 구성
● 관계
○ 개념: 서로 다른 개체가 맺고 있는 의미 있는 연관성 / 개체 사이의 대응 관계, 매핑(Mapping)을 의미
○ 유형
○ 참여 특성
- 필수적 참여: 전체 참여 / 개체가 관계에 반드시 참여해야 되는 것
- 선택적 참여: 부분 참여 / 개체 중 일부만 관계에 참여해도 되는 것
○ 관계 결정
- 요구사항 문장에서 개체 간의 관계를 표현한 동사를 찾고, 의미가 같은 동사가 있을 경우 대표적인 것 하나만 선택
- 찾아낸 관계에 대해 1:1, 1:n, n:m 그리고 ㅍ필수적 참여, 선택적 참여인지 결정
- ex) 온라인 강의 사이트
관계 데이터 모델
● 데이터 모델
○ 계층 데이터 모델: 트리 데이터, 부모 자식 관계 / ex) IMS, System 2000
○ 네트워크 데이터 모델: 망 데이터 모델, 그래프 형태로 표현 / ex) DBTG, IDMS, ids2, Total, DMS/1100
○ 관계 데이터 모델: 표 데이터 모델, 구조 단순, 사용 편리 / ex) DB2, SQL Sever, Oracle, Mysql
● 관계형 데이터 모델
○ 개념: 현실 세계의 모든 데이터를릴레이션 구조로 구성 / DB의 논리/물리적인 면을 구분해 데이터 독립성 향상 / 단순한 구조
○ 용어
- 릴레이션: 정보 저장의 형태가 2차원 구조의 테이블
- 속성: 테이블의 각 열을 의미
- 트퓰: 테이블의 한 행을 구성하는 속성들의 집합, 레코드
- 도메인: 속성이 취할 수 있는 값들의 집합
- 기수: 튜플의 수, Cardinality
- 차수: 속성의 수, Degree
○ 릴레이션 특징
- 특정 릴레이션은 오직 하나의 레코드 타입만 저장
- 하나의 속성 내의 값들은 모두 같은 유형
- 속성들의 순서는 중요하지 않음
- 각 속성의 이름은 한 릴레이션 내에서 고유함, 다른 릴레이션에선 존재 가능
- 릴레이션에서 동일한 튜플이 두 개 이상 존재하지 않음
- 한 튜플의 각 속성은 원자 값을 가짐, 값에 리스트나 집합 등은 허용X
○ 키의 종류
- 슈퍼키: 유일성O, 최소성X
- 후보키: 유일성O, 최소성O
- 기본키: 개체 식별자, 튜플을 유일하게 식별할 수 있는 속성의 집합
- 대체키: 기본키를 제외한 후보키
- 외래키 다른 테이블을 참조하는데 사용되는 속성 R1속성이 R2를 참조할때 R1에 속한 외래키 속성의 값은 참조하는 R2의 기본키가 됨
● 무결성과 제약조건종류
○ 데이터 무결성
- 현실 세계의 실제 값과 DB에 저장된 값이 일치하는 정확성을 의미
- DB 내에 존재하는 데이터가 항상 유효한 데이터가 되도록 제약 조건을 적용
- 무결성 제약 조건은 데이터베이스 상태가 만족시켜야 하는 조건
○ 무결성 제약조건
- 개채 무결성: 기본 릴레이션의 기본키를 구성하는 어떤 속성도 NULL, 중복을 허용하지 않음
- 참조 무결성: 외래키 값은 NULL 이거나, 참조하는 릴레이션에 있는 기본키
- 도메인 무결성: 특정 속성의 값은 그 속성에 정의된대로의 값만 허용
● 사상(Mapping)
DB 설치, 연동
# MariaDB 설치, 실행
yum install mariadb-server
systemctl restart mariadb
setenforce 0
systemctl stop firewalld
mysql
# 유저 생성
CREATE USER '[이름'] '@ '%' IDENTIFIED BY '[비밀번호]'
# 스키마 생성
CREATE DATABASE [DB이름]
# 관리자 권한으로 설정된 스키마에 접속할 수 있게 유저에게 권한 부야ㅕ
GRANT ALL PRIVILEGES ON [DB이름].* TO '[이름]'@'%'
# MySQL Workbench 연결 설정
connection name: 아무거나
hostname: CentOS 머신의 IP
포트번호: 3306
생성한 아이디, 비밀번호
# Reverse engineer -> erd 작성
# forward engineer -> sql 생성 -> INDEX, CONSTRAINT라인 삭제
# 스키마에서 쿼리 입력
○ 실습: LMS
○ 실습: 쇼핑몰
정규화
● 정규화
○ 이상 문제를 해결하기 위해 속성 간 종속 관계를 분석, 릴레이션을 분해하는 과정
○ 릴레이션의 속성 개체, 관계를 파악해 데이터의 중복성을 최소화하는 과정
○ DB의 물리적 구조나 물리적 처리에 영향을 주는 것이 아닌 논리적 처리에 영향
○ 정규화를 통해 릴레이션을 분해하면 일반적으로 연산 시간은 증가
● 이상
○ 속성 간에 존재하는 여러 종속 관계를 하나의 릴레이션에 표현함으로 인해 발생하는 현상
○ 삽입 이상: 데이터를 저장할 때 원하지 않는 정보가 함께 삽입되는 경우
○ 삭제 이상: 튜플을 삭제함으로써 유지되어야 하는 정보까지도 연쇄적으로 삭제
○ 갱신 이상: 중복된 튜플 중 일부의 속성만 갱신시킴으로써 정보의 모순성 발생
● 함수적 종속
○ 개념: 어떤 릴레이션에서 속성들의 부분 집합을 X, Y라 할때 특정 튜플에서 X의 값이 Y의 값을 함수적으로 결정한다면 Y가 X에 함수적종속
○ 추론 규칙
- 재귀 규칙: Y가 X의 부분집합이면 X->Y
- 증가 규칙: X->Y이면 WX->WY이고 WX->Y
- 이행 규칙: X->Y이고 Y->Z이면 X->Z
- 유니온 규칙: X->Y이고 Y->Z이면 X->Z
- 분해 규칙: X->YZ이면 X->Y와 X->Z
- 가이행 규칙: 만일 W->X이고 XY->Z이면 WX->Z
● 제 1 정규형: 도메인 모두 원자값으로 변경
● 제 2 정규형: 부분 함수 종속 제거
● 제 3 정규형: 이행 함수 종속 제거
● BCNF: 결정자 중 후보키가 아닌 것들은 제거
● 제 4 정규형: 다치 종속 제거
● 제 5 정규형: 조인 종속성 제거
SQL
● SQL
○ 70년대 초 IBM에서 관계형 데이터베이스 관리 시스템에서 저장된 데이터를 다루기 위해 개발
○ 관계대수, 해석을 기초로한 고급 데이터 언어
○ 데이터 정의, 조작, 제어 기능을 제공하는 비절차적 언어 / 종류는 DDL, DML, DCL
● DDL: 스키마, 도메인, 테이블, 뷰, 인덱스 등 데이터의 구조를 정의하거나 제거
# CREATE
CREATE TABLE [테이블 이름] (
[속성 이름] [타입],
# 기본키 1 [속성 이름] [타입] PRIMARY KEY,
# 기본키 2 [CONSTRAINT 제약조건 이름] PRIMARY KEY (속성 이름)
...
# 외래키
[CONSTRAINT 제약조건이름]
FOREIGN KEY (속성이름)
REFERENCES [참조 테이블 이름](속성이름)
);
# ALTER
ALTER TABLE [테이블 이름] ADD [속성 이름][타입]
ALTER TABLE [테이블 이름] DROP (속성 이름)[CASCADE]
ALTER TABLE [테이블 이름] RENAME COLUMN [속성 이름] TO [변경 이름]
ALTER TABLE [테이블 이름] MODIFY [속성 이름][타입]
# DROP
DROP TABLE [테이블 이름] [CASCADE or RESTRICTED]
* CASCADE: 개체를 변경/삭제할 때 다른 개체가 변경/삭제할 개체를 참조하고 있을 경우 함께 변경/삭제
* RESTRICTED: 개체를 변경/삭제할 때 다른 개체가 변경/삭제할 개체를 참조하고 있을 경우 변경/삭제가 취소(제한)
# 실습
CREATE TABLE video (
id INT auto_increment primary KEY, # id 속성, 숫자만 저장, 저장할 때 숫자 자동 증가, 기본키
name varchar(20), # name 속성, 문자 20개 저장
url varchar(100), # url 속성, 문자 100개 저장
member_id INT, # member_id 속성, 숫자만 저장
foreign key (member_id) references member (id) # 이 테이블에서 member_id속성을 member 테이블의 id 속성을 참조하는 외래키로 설정
);
CREATE TABLE member (
id INT(11) auto_increment primary KEY,
email varchar(20),
password varchar(30),
name varchar(20)
);
CREATE TABLE likes (
id INT PRIMARY KEY,
member_id INT(11),
foreign key(member_id) references member (id),
bbs_id INT,
foreign key(bbs_id) references bbs (id)
);
CREATE TABLE bbs (
id INT PRIMARY KEY,
title VARCHAR(45),
contents VARCHAR(45),
member_id INT(11),
foreign key (member_id) references member(id)
);
CREATE TABLE image (
id INT PRIMARY KEY,
filename VARCHAR(45),
bbs_id INT,
foreign key (bbs_id) references bbs(id)
);
ALTER TABLE video ADD playtime int;
ALTER TABLE video MODIFY playtime varchar(10);
ALTER TABLE video CHANGE playtime play varchar(10);
ALTER TABLE video DROP play;
● DML: 실질적으로 데이터를 조회, 삽입, 삭제, 수정할 때 사용하는 SQL
# INSERT
INSERT INTO [테이블 이름] (속성 이름, ...) VALUE (값, ...);
INSERT INTO [테이블 이름] VALUES (값, ...);
# DELETE
DELETE FROM [테이블 이름] WHERE [조건];
# UPDATE
UPDATE [테이블 이름] SET [속성 이름] = [값], ... WHERE [조건];
# SELECT
SELECT [속성 이름] FROM [테이블 이름] WHERE [조건]; GROUP BY / HAVING / ORDER BY
# 연습
INSERT INTO member VALUE
(1, 'test1@test.com', 'qwer1234', 'test1'),
(2, 'test2@test.com', 'qwer1234', 'test2'),
(3, 'test3@test.com', 'qwer1234', 'test3'),
(4, 'test4@test.com', 'qwer1234', 'test4'),
(5, 'test5@test.com', 'qwer1234', 'test5'),
(6, 'test6@test.com', 'qwer1234', 'test6');
UPDATE member SET password ='12345678' WHERE id = '1';
DELETE FROM member where id ='2';
SELECT * FROM member;
# guests 테이블에서 guest_id, name 속성들을 조회
SELECT guest_id, name FROM guests;
# guests 테이블에서 모든 속성 조회, 실무에선 필요한 속성만 선택해 조회
SELECT * FROM guests;
# 그림1 특정 원하는 데이터만 조회, OR, AND 사용시 SQL 인젝션
SELECT * FROM guests WHERE guest_id > 3 AND guest_id <= 4;
# INNER JOIN
SELECT 속성, ... FROM 테이블1 INNER JOIN 테이블2 ON 테이블1.속성 = 테이블2.속성
# LEFT JOIN
SELECT 속성, ... FROM 테이블1 LEFT JOIN 테이블2 ON 테이블1.속성 = 테이블2.속성
# RIGHT JOIN
SELECT 속성, ... FROM 테이블1 RIGHT JOIN 테이블2 ON 테이블1.속성 = 테이블2.속성
# UNION
SELECT 속성1, ... FROM 테이블1 UNION SELECT 속성1, ... FROM 테이블2
SELECT * FROM countries LEFT JOIN regions ON countries.region_id = regions.region_id;
SELECT * FROM countries LEFT JOIN regions ON countries.region_id = regions.region_id where countries.region_id = 1;
SELECT * FROM continents LEFT JOIN regions ON regions.continent_id = continents.continent_id;
# 그림2
SELECT * FROM countries
LEFT JOIN country_languages
ON countries.country_id = country_languages.country_id
LEFT JOIN languages
ON country_languages.language_id = languages.language_id
ORDER BY countries.area ASC, languages.language_id ASC;
# LIKE
SELECT [속성] FROM [테이블이름] WHERE [속성] LIKE '%찾고자하는문자열%'
SELECT * FROM countries WHERE national_day IS NULL; # 비어있는 것 찾을 때는 IS NULL
# 그림3
SELECT * FROM countries WHERE name LIKE '%me%'; # me가 포함된 것 찾을 때
SELECT * FROM countries WHERE name NOT LIKE '%me%'; # me가 포함되지 않은 것 찾을 때
# LIMIT
SELECT [속성] FROM [테이블이름] WHERE [속성] LIMIT [제한걸튜플수]
SELECT * FROM countries LIMIT 10; # 맨 처음부터 10개 조회
# 그림4
SELECT * FROM countries LIMIT 5, 3; # 5번 다음부터 3개 조회
# 내장함수: SUM, COUNT, AVG, RIGHT, SUBSTRING, INDEX, UPPER, NOW, CURDATE, CURTIME
# SUM / countries 테이블에서 area의 모든 값을 더한 값을 출력
SELECT SUM(area) FROM countries;
# GROUP BY: 특정열 또는 특정 열을 연산한 결과를 집계해 그 집계값에 따라 그룹을 짓는 연산자
# HAVING: GROUP BY 결과에 조건을 걸어 데이터를 조회하고 싶을 때 사용, GROUP BY의 WHERE 절
# 그림5 countries 테이블에서 region_id별 area의 평균 중에서 평균이 10000보다 큰 것만 출력
SELECT region_id, AVG(area) FROM countries GROUP BY region_id HAVING AVG(area) > 10000;
# 서브쿼리
SELECT, INSERT, UPDATE, DELETE, SET, DO 문을 사용할 때 해당 쿼리 내부에 또 다른 쿼리를 사용하는 것
SELECT * FROM countries WHERE region_id = ANY(SELECT region_id FROM regions);
● DCL: 데이터베이스에 접근하고 사용할 수 있도록 권한을 주고 회수하는 명령어
# GRANT
GRANT [권한명] on [DB].[TABLE] to [계정명];
GRANT ALL PRIVILEGES ON *.* TO ‘user01’@’%’ WITH GRANT OPTION;
# REVOKE
REVOKE [권한명] on [DB].[TABLE] FROM [계정명]
# 권한 종류
CREATE, ALTER, DROP: 테이블 생성, 변경, 삭제
ALL: 모든 권한 허용
USAGE: 권한 없이 계정만 생성
● View, Index
○ 뷰
- 하나 이상의 테이블로부터 유도되어 만들어진 가상 테이블 / 실행시간에만 구체화되는 특수한 테이블
- 다른 테이블이나 다른 뷰에 저장되어 있는 데이터를 보여주는 역할만을 수행 / 실제 테이블처럼 행과 열을 가지지만, 실제 데이터를 저장하는 것이 아님
- 장점: 특정 사용자에게 테이블 전체가 아닌 필요한 부분만을 보여주기 가능 / 복잡한 쿼리 단순화 / 쿼리 재사용 가능
- 단점: 삽입, 삭제, 갱신 작업에 많은 제한 사항이 존재 / 자신만의 인덱스를 가질 수 없음
# 생성
CREATE VIEW [뷰이름] AS SELECT 속성, ... FROM [테이블 이름] WHERE [조건]
# 삭제
DROP VIEW [뷰이름]
○ 인덱스
- 테이블에서 원하는 데이터를 쉽고 빠르게 찾기 위해 사용 / 자주 사용되는 속성으로 만들어진 원본 테이블의 사본과도 같은 것
- DBMS는 DB에서 데이터를 검색할 때 테이블에서 내용으로 하나하나 검색, 테이블이 크면 클수록 데이터를 검색하는 시간이 느려짐, 인덱스를 사용하면 테이블 전체를 읽지 않아 검색 성능 증가
# 생성
CREATE INDEX [인덱스 별칭] ON [테이블 이름] (속성, ...)
# 조회
SHOW INDEX FROM [테이블 이름]
# 삭제
ALTER TABLE [테이블 이름] DROP INDEX [인덱스 별칭]
실습 - 코테
# 프로그래머스-과일로 만든 아이스크림 고르기
SELECT FIRST_HALF.FLAVOR FROM FIRST_HALF
LEFT JOIN ICECREAM_INFO ON FIRST_HALF.FLAVOR = ICECREAM_INFO.FLAVOR
WHERE TOTAL_ORDER >= 3000 and INGREDIENT_TYPE = 'fruit_based'
ORDER BY FIRST_HALF.TOTAL_ORDER DESC
# 프로그래머스-있었는데요 없었습니다
SELECT ANIMAL_INS.ANIMAL_ID, ANIMAL_INS.NAME FROM ANIMAL_OUTS
LEFT JOIN ANIMAL_INS ON ANIMAL_OUTS.ANIMAL_ID = ANIMAL_INS.ANIMAL_ID
WHERE ANIMAL_INS.DATETIME > ANIMAL_OUTS.DATETIME ORDER BY ANIMAL_INS.DATETIME ASC;
# 프로그래머스-오랜 기간 보호한 동물
SELECT ANIMAL_INS.NAME, ANIMAL_INS.DATETIME FROM ANIMAL_INS
LEFT JOIN ANIMAL_OUTS ON ANIMAL_OUTS.ANIMAL_ID = ANIMAL_INS.ANIMAL_ID
WHERE ANIMAL_OUTS.ANIMAL_ID IS NULL ORDER BY ANIMAL_INS.DATETIME ASC LIMIT 3;
# 프로그래머스-보호소에서 중성화한 동물
SELECT ANIMAL_INS.ANIMAL_ID, ANIMAL_INS.ANIMAL_TYPE, ANIMAL_INS.NAME FROM ANIMAL_INS
LEFT JOIN ANIMAL_OUTS ON ANIMAL_OUTS.ANIMAL_ID = ANIMAL_INS.ANIMAL_ID
WHERE ANIMAL_INS.SEX_UPON_INTAKE = 'Intact Female' AND ANIMAL_OUTS.SEX_UPON_OUTCOME ='Spayed Female' OR ANIMAL_INS.SEX_UPON_INTAKE = 'Intact Male' AND ANIMAL_OUTS.SEX_UPON_OUTCOME = 'Neutered Male'
ORDER BY ANIMAL_INS.ANIMAL_ID ASC;
# 프로그래머스-카테고리 별 도서 판매량 집계하기
SELECT CATEGORY, SUM(BOOK_SALES.SALES) AS TOTAL_SALES
FROM BOOK LEFT JOIN BOOK_SALES
ON BOOK.BOOK_ID = BOOK_SALES.BOOK_ID
WHERE BOOK_SALES.SALES_DATE LIKE '2022-01-%'
GROUP BY CATEGORY
ORDER BY BOOK.CATEGORY ASC;
# 프로그래머스-대여 횟수가 많은 자동차들의 월별 대여 횟수 구하기 (반품)
SELECT MONTH(START_DATE), CAR_ID, COUNT(*) AS RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE >= '2022-08-01' AND START_DATE <= '2022-10-31'
AND CAR_ID
IN (SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE >= '2022-08-01' AND START_DATE <= '2022-10-31'
GROUP BY CAR_ID
HAVING COUNT(HISTORY_ID) >= 5)
GROUP BY MONTH(START_DATE), CAR_ID
HAVING RECORDS >= 0
ORDER BY MONTH(START_DATE) ASC, CAR_ID DESC