SQL

Structured Query Language (SQL)은 데이터베이스 언어로, 주로 관계형 데이터베이스에서 사용합니다. Query 란 데이터를 필터링하기 위한 질의문입니다.

DB 생성

CREATE DATABASE [DB 명]

데이터 베이스 사용

USE [DB 명]

테이블 생성

CREATE TABLE user (
  id int PRIMARY KEY AUTO_INCREMENT, 
  name varchar(255),
  email varchar(255)
);

테이블 정보 확인

DESCRIBE user

SQL 명령어

SELECT + FROM

특정 테이블에서 특정 필드를 선택합니다.

SELECT * FROM [TABLE 명] #TABLE 의 모든 필드를 가져옵니다.
SELECT NAME FROM [TABLE 명] #TABLE 에서 NAME 필드를 가져옵니다.

WHERE

필터역할을 하는 쿼리문입니다.

SELECT * FROM [TABLE 명] WHERE NAME="KIM" #TABLE 에서 NAME 필드가 "KIM" 인 모든 레코드를 가져옵니다.
SELECT * FROM [TABLE 명] WHERE NAME<>"KIM" #TABLE 에서 NAME 필드가 "KIM" 이 아닌 모든 레코드를 가져옵니다.
SELECT * FROM [TABLE 명] WHERE NOT NAME = "KIM" #TABLE 에서 NAME 필드가 "KIM" 이 아닌 모든 레코드를 가져옵니다. 위와 같습니다.
SELECT * FROM [TABLE 명] WHERE NAME LIKE "KIM%" #TABLE 에서 NAME 필드가 "KIM" 으로 시작하는 모든 레코드를 가져옵니다.
SELECT * FROM [TABLE 명] WHERE ID IN (1, 10) #TABLE 에서 ID 필드가 1 ~ 10 인 모든 레코드를 가져옵니다.
SELECT * FROM [TABLE 명] WHERE EMAIL IS NULL #TABLE 에서 EMAIL 필드가 NULL 값인 모든 레코드를 가져옵니다.
SELECT * FROM [TABLE 명] WHERE EMAIL IS NOT NULL #TABLE 에서 EMAIL 필드가 NULL 값이 아닌 모든 레코드를 가져옵니다.

ORDER BY

데이터 출력하는 순서를 결정합니다.

SELECT * FROM [TABLE 명] ORDER BY ID #TABLE 에서 모든 레코드를 ID 값의 오름차순으로 정렬하여 가져옵니다.
SELECT * FROM [TABLE 명] ORDER BY NAME #TABLE 에서 모든 레코드를 NAME 값의 오름차순으로 정렬하여 가져옵니다.
SELECT * FROM [TABLE 명] ORDER BY ID DESC #TABLE 에서 모든 레코드를 ID 값의 내림차순으로 정렬하여 가져옵니다.
SELECT * FROM [TABLE 명] ORDER BY ID, NAME #TABLE 에서 모든 레코드를 ID 값의 오름차순으로 정렬하고 같으면 NAME 값의 오름차순으로 정렬하여 가져옵니다.

LIMIT

결과로 출력할 데이터의 개수를 정할 수 있습니다. LIMIT은 선택적으로 사용할 수 있습니다. 그리고 쿼리문에서 사용할 때에는 가장 마지막에 추가합니다.

SELECT * FROM [TABLE 명] LIMIT 200 #TABLE 에서 200 개의 레코드를 가져옵니다.

DISTINCT

특정 필드의 중복을 제거한 뒤 결과를 출력합니다. 아래는 USER 테이블입니다.

ID NAME EMAIL
1 KIM EMAIL1@NAVER.COM
2 KIM EMAIL2@NAVER.COM
3 PARK EMAIL2@NAVER.COM
SELECT DISTINCT NAME FROM USER # 1, 3번 아이디만 출력됩니다.
SELECT DISTINCT EMAIL FROM USER # 1, 2번 아이디만 출력됩니다.
SELECT DISTINCT NAME, EMAIL FROM USER # 1번 아이디만 출력됩니다.

INNER JOIN

INNER JOIN 은 테이블을 병합하기 위해 사용합니다. DISTINCT 의 USER 테이블과 아래의 POST, REWARD 테이블을 함께 사용하겠습니다.

POST TABLE

ID TITLE CONTENT USER_ID
1 TITLE1 CONTENT1 1
2 TITLE2 CONTENT2 1
3 TITLE3 CONTENT3 2

REWARD TABLE

ID REWARD USER_ID
1 1000 2
2 2000 3
SELECT U.ID, P.TITLE, P.CONTENT FROM USER AS U JOIN POST AS P ON U.ID = P.USER_ID

JOIN 은 두 개 이상의 테이블을 결합하기 때문에 결합하는 테이블의 필드명이 중복될 수 있습니다. 따라서 위 쿼리문처럼 필드가 속한 테이블을 명시해줍니다. 위 쿼리문 시행 시 아래와 같은 결과를 얻습니다.

U.ID P.TITLE P.CONTENT
1 TITLE1 CONTENT1
1 TITLE2 CONTENT2
2 TITLE3 CONTENT3

다음은 삼중 JOIN 을 해보겠습니다.

SELECT U.ID, P.TITLE, R.REWARD FROM USER AS U JOIN POST AS P ON U.ID = P.USER_ID JOIN REWARD AS R ON P.USER_ID = R.USER_ID
SELECT U.ID, P.TITLE, R.REWARD FROM USER AS U JOIN REWARD AS R ON U.ID = R.USER_ID JOIN POST AS P ON R.USER_ID = P.USER_ID
SELECT U.ID, P.TITLE, R.REWARD FROM USER AS U JOIN POST AS P ON U.ID = P.USER_ID JOIN REWARD AS R ON U.ID = R.USER_ID
SELECT U.ID, P.TITLE, R.REWARD FROM USER AS U JOIN REWARD AS R ON U.ID = R.USER_ID JOIN POST AS P ON U.ID = P.USER_ID

위 네 결과는 같습니다. USER 와 POST, RECORD 테이블이 모두 겹치는 경우만 출력합니다.

U.ID P.TITLE R.REWARD
2 TITLE3 CONTENT3

OUTER JOIN

외부 조인은 한쪽 테이블에만 내용이 있어도 결과가 검색이 됩니다. LEFT JOIN, RIGHT JOIN 과 같이 사용될 수 있는데, LEFT 는 첫번째 테이블은 모두 검색되어야 한다는 뜻이고, RIGHT 는 반대입니다.

SELECT U.ID, P.TITLE FROM USER AS U LEFT JOIN POST AS P ON U.ID = P.USER_ID
U.ID P.TITLE
1 TITLE1
1 TITLE2
2 TITLE3
3 NULL

GROUP BY

GROUP BY 는 데이터를 조회할 때 그룹으로 묶어서 조회합니다.

ID CUSTOMER_ID TOTAL STATE
1 1 100 A
2 1 150 A
3 1 150 B
4 2 200 B
5 2 300 C

위와 같은 테이블이 있다고 했을 때 STATE 별 GROUP BY 를 해보겠습니다.

SELECT * FROM INVOICES GROUP BY STATE;

결과는 아래와 같이 나옵니다.

ID CUSTOMER_ID TOTAL STATE
1 1 100 A
3 1 150 B
5 2 300 C

그룹에 대한 특별한 작업이 없다면, 각 그룹의 첫번째 데이터만 표시됩니다. 따라서 그룹핑 어떠한 값으로 할지 정해야 합니다.

SELECT CUSTOMER_ID, AVG(TOTAL) FROM INVOICES GROUP BY CUSTOMER_ID HAVING AVG(TOTAL) > 100.00

테이블에서 CUSTOMER_ID 로 그룹핑하는데, HAVING 을 사용해서 AVG(TOTAL) 가 100.00 이 넘는 레코드만 표시합니다.

CUSTOMER_ID AVG(TOTAL)
1 100
2 150

COUNT(), SUM(), AVG(), MAX(), MIN()

각 함수는 사용법이 비슷합니다. 아래 예시는 COUNT() 로, 레코드의 개수를 헤아릴 때 사용합니다.

SELECT STATE, COUNT(*) FROM INVOICES GROUP BY STATE

각 STATE 별 개수를 알 수 있습니다.

SELECT 실행 순서

SELECT 실행 순서는 다음과 같습니다.

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

HAVING 까지 모든 과정이 끝난 후 각 레코드 값을 가져옵니다. 그리고 ORDER BY 로 정렬합니다.

트랜잭션

​ 트랜잭션이란 여러 개의 작업을 하나로 묶은 실행 유닛입니다. 각 트랜잭션은 하나의 특정 작업으로 시작을 해 묶여 있는 모든 작업들을 다 완료해야 정상적으로 종료합니다. 반대로 한 작업이라도 실패한다면 이 트랙잭션에 속한 모든 작업을 실패한 것으로 간주합니다. 이러한 트랜잭션의 안전성을 보장하기 위해 ACID 라는 성질이 필요합니다.

Atomicity (원자성)

​ 원자성은 하나의 트랜잭션에 속해있는 모든 작업이 전부 성공하거나 전부 실패해서 결과를 예측할 수 있어야 합니다.

Consistency (일관성)

​ 두 번째는 데이터베이스의 상태가 일관되어야 한다는 성질입니다. 하나의 트랜잭션 이전과 이후, 데이터베이스의 상태는 이전과 같이 유효해야 합니다. 다시 말해, 트랜잭션이 일어난 이후의 데이터베이스는 데이터베이스의 제약이나 규칙을 만족해야 한다는 뜻입니다.

Isolation(격리성, 고립성)

​ Isolation(격리성) 은 모든 트랜잭션은 다른 트랜잭션으로부터 독립되어야 한다 는 뜻입니다. 예를 들어서 한 계좌에서 다른 계좌로 2번 송금을 하는 상황에서 동시에 트랜잭션을 실행하든, 연속적으로 실행하든 같은 결과가 나와야 합니다. 즉, 격리성을 지키는 각 트랜젝션은 철저히 독립적이기 때문에, 다른 트랜젝션의 작업 내용을 알 수 없습니다. 그리고 트랜잭션이 동시에 실행될 때와 연속으로 실행될 때의 데이터베이스 상태가 동일해야 합니다.

Durability(지속성)

​ Durability(지속성)는 하나의 트랜잭션이 성공적으로 수행되었다면, 해당 트랜잭션에 대한 로그가 남아야 합니다. 만약 런타임 오류나 시스템 오류가 발생하더라도, 해당 기록은 영구적이어야 한다는 뜻입니다.

​ 예를 들어 은행에서 계좌이체를 성공적으로 실행한 뒤에, 해당 은행 데이터베이스에 오류가 발생해 종료되더라도 계좌이체 내역은 기록으로 남아야 합니다.

SQL DB vs NoSQL DB

SQL 과 NoSQL 에는 다음과 같은 차이점이 있습니다.

  • 데이터 저장 : SQL 은 미리 작성된 스키마를 기반으로 테이블을 사용해 저장하는 반면 NoSQL 은 key-value, document, wide-column, graph 등의 방식으로 데이터를 저장합니다.
  • 스키마 : SQL 은 필드를 만드는 등의 고정된 형식의 스키마가 있어야 합니다. 하지만 NoSQL 은 동적으로 스키마를 관리할 수 있습니다.
  • 쿼리 : SQL 은 이름 그대로 구조화된 쿼리 언어로 질의합니다. 하지만 NoSQL 은 데이터 그룹 자체를 조회하는 것에 초점을 두고 있습니다. 그래서 구조화되지 않은 쿼리 언어로도 데이터 요청이 가능합니다.
  • 확장성 : SQL 은 일반적으로 scale up 을 하고 NoSQL 은 scale out 을 합니다. SQL 도 scale out 이 가능하지만 여러 서버에 결쳐 관계를 정의하는 것은 매우 복잡하고 시간이 많이 소ㅗㅁ됩니다.

SQL 기반의 RDMS 를 사용하는 경우

  1. 데이터베이스의 ACID 성질을 준수해야 하는 경우
  2. 소프트웨어에 사용되는 데이터가 구조적이고 일관적인 경우

NoSQL 기반의 NonRDMS 를 사용하는 경우

  1. 데이터의 구조가 거의 또는 전혀 없는 대용량의 데이터를 저장하는 경우
  2. 클라우드 컴퓨팅 및 저장공간을 최대한 활용하는 경우
  3. 빠르게 서비스를 구축하는 과정에서 데이터 구조를 자주 업데이트 하는 경우

댓글남기기