관계형 데이터베이스에서 데이터를 조회하거나 정의 및 조작하기 위해 사용하는 표준 언어
선언형 고급 언어(Declarative High-Level Language)로 고급 언어보다 더 높은 단계의 언어이다.
데이터를 무엇을 할지(What) 선언 하면, 어떻게 처리할지(How)는 DBMS가 알아서 처리한다.
| 분류 | 상위 타입 | 하위 타입 및 크기 | 설명 |
|---|---|---|---|
| 수치형 (Numeric) | 정수형 (Integer) | SMALLINT (2B) INTEGER/INT (4B) BIGINT (8B) | 정수 저장, 크기에 따라 범위 다름 INTEGER ↔ INT 별칭 존재 |
| 실수형 (Float) | REAL (4B) DOUBLE PRECISION (8B) | 부동소수점 또는 고정소수점 저장 | |
| 임의 정밀도 | NUMERIC, DECIMAL | 지정된 정밀도의 소수 저장, 금융 데이터 적합 예: NUMERIC(4,2) → 총 4자리, 소수점 2자리 | |
| 시퀀스형 | SMALLSERIAL (2B) SERIAL (4B) BIGSERIAL (8B) | 내부적으로 시퀀스 기반 자동 증가 정수 AUTO INCREMENT 전용 | |
| 문자형 (String) | 고정길이 문자 | CHAR(n) | 설정된 길이보다 짧으면 공백으로 채움 검색 속도 및 인덱스 구성에 유리 |
| 가변길이 문자 | VARCHAR, VARCHAR(n) | 가변 길이 문자, 행 크기로 8KB 제한 최대 크기 지정 가능 | |
| TEXT | TEXT | 길이 제한 없음, VARCHAR와 동일 문법 | |
| 논리형 | BOOLEAN | BOOLEAN (1B) | 참/거짓 표현 (TRUE, FALSE, NULL 가능) |
| Binary | BYTEA | BYTEA | Binary Data 저장 (이미지, 음성 등) 최대 크기: 65,535 / 16,777,215 / 4,294,967,295 |
| Date Time | DATE | DATE | 연, 월, 일 저장 |
| TIME | TIME TIME WITH TIME ZONE (TIMEZ) | 시, 분, 초 저장 TIMEZ는 별칭으로, 타임존 정보 포함 | |
| TIMESTAMP | TIMESTAMP TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) | 날짜와 시간 저장 (UTC 기준) WITH TIME ZONE 사용 시 타임존 적용 TIMESTAMPTZ는 별칭 | |
| 열거/배열 | ENUM | CREATE TYPE gender AS ENUM ('male','female'); | 사전에 정의된 문자열 집합 중 하나만 선택 |
| datatype[] | 예: interests TEXT[] | 동일 타입 요소들의 배열 저장 가능 | |
| 기타 | JSON | JSON, JSONB | JSON 객체 구조 저장 가능 JSONB는 바이너리 최적화 및 빠른 검색 지원 |
| UUID | UUID | 범용 고유 식별자 (Universally Unique Identifier) | |
| 범위 (Range) | int4range, int8range, numrange, tsrange, tstzrange, daterange | 값의 구간을 표현하는 타입 (숫자, 날짜, 시간 등) | |
| 네트워크 주소 | INET, CIDR, MACADDR | IP 주소, 네트워크 대역, MAC 주소 저장 | |
| 기타 특수 | XML, tsvector, tsquery, point, line, circle, box, polygon | XML 데이터, Full-text 검색(tsvector/tsquery), 공간/수학 관련 타입 |
DB 스키마 전환은 데이터베이스 내에서 객체가 속하는 논리적 공간을 변경하는 개념이다.
PostgreSQL은 데이터베이스와 스키마를 구분하여 관리한다. 데이터베이스 전환은 연결 변경으로, 스키마 전환은 SET search_path로 수행한다. 이후 DB의 이름을 생략할 수 있다.
Ex) SELECT FROM schema_name.table_name → SELECT FROM table_name
-- 1. 데이터베이스 생성
CREATE DATABASE my_database;
-- 2. 연결된 DB 안에서 스키마 생성
CREATE SCHEMA my_schema;
-- 3. 스키마 삭제
DROP SCHEMA my_schema CASCADE;
-- 4. 특정 스키마를 기본 검색 경로로 설정
SET search_path TO my_schema;
COMMIT;
SELECT는 관계형 데이터베이스에서 원하는 데이터를 조회(Query)하기 위한 기본적인 SQL 명령어
조회한 결과는 Result Set이라 말하며, SELECT구문에 의해 반환된 행들의 집합을 의미
Result Set은 0개 이상의 행이 포함될 수 있이며, 특정 기준에 의해 정렬 가능
한 테이블의 특정 컬럼, 행, 행/컬럼 또는 여러 테이블의 특정 행/컬럼 조회 가능
SELECT * FROM employee
SELECT 컬럼 [, 컬럼, …] ← 컬럼명 소문자 권장
FROM 테이블 ← 테이블명 소문자 권장
WHERE 조건식; ← 조건식 컬럼명은 소문자 키워드는 대문자 권장
조회하고자 하는 컬럼명 기술
여러 컬럼을 조회하는 경우 컬럼은 쉼표로 구분하고, 마지막 컬럼 다음은 쉼표를 사용하지 않음
모든 컬럼 조회 시 컬럼 명 대신 * 기호 사용 가능하며 조회 결과는 기술한 컬럼 명 순으로 표시 됨
조회 대상 컬럼이 포함된 테이블 명을 기술, DB 명이 앞에 붙어도 무관
행을 선택하는 조건 기술
여러 개의 제한 조건을 포함할 수 있으며, 각각의 제한 조건은 논리 연산자로 연결
제한 조건을 만족시키는 행들만 Result Set에 포함
-- 직원 전부의 사번과 이름, 월급을 조회하는 구문
SELECT emp_id, emp_name, salary
FROM codeit.employee;
-- 또는
SELECT emp_id, emp_name, salary
FROM employee;
-- 직원 전부의 모든 정보를 조회하는 구문 → Full scan이 말한다.
SELECT emp_id, emp_name, emp_no, email, phone, dept_code,
job_code, sal_level, salary, bonus, manager_id, hire_date,
ent_date, ent_yn
FROM employee;
-- 또는
SELECT * FROM employee; → *로 컬럼명, SPACE 생략 가능! *은 개발 시 추천하지 않음
-- 컬럼 값에 대해 산술 연산한 결과 조회 가능
SELECT emp_name, salary * 12, (salary + (salary*bonus)) * 12
FROM employee;
-- 'AS 별칭', '별칭' 또는 'AS "별칭"'을 기술하여 컬럼 별칭을 지을 수 있음
-- → 매우 유용한 스킬로 DB 연동 시 컬럼명 기준임으로 복잡한 컬럼명 단축이 가능
SELECT emp_name AS 이름, salary * 12 "연봉(원)",
(salary + (salary * bonus)) * 12 AS "총 소득(원)"
FROM employee;
-- * 숫자 혹은 특수문자가 포함되는 경우에 " " 사용
-- * AS 생략 가능(공백으로 구분)
-- 임의로 지정한 문자열을 SELECT절에 사용하면 테이블에 존재하는 데이터처럼 활용
SELECT emp_id, salary, '원' AS 단위
FROM employee;
-- * 문자나 날짜 리터럴은 ‘ ‘ 기호 사용
-- * 리터럴은 Result Set의 모든 행에 반복 표시 됨
-- 컬럼에 포함된 데이터 중복된 데이터를 제거하고 유일한 값만 조회할 때 사용,
-- 여러 컬럼 기준으로도 중복제거가 가능하며 count절과 조합하면 중복이 제거된 수를 알 수 있음
SELECT DISTINCT job_code FROM employee; → SELECT count(DISTINCT job_code) FROM employee;
SELECT DISTINCT job_code, dept_code FROM employee;
-- 검색할 컬럼의 조건을 설정하여 행 결정, 이때 조건은 다중 논리 조건 활용 가능
-- - 부서코드가 ‘D9’인 직원의 이름, 부서코드 조회
SELECT emp_name, dept_code
FROM employee
WHERE dept_code = 'D9';
-- - 부서코드가 ‘D2’보다 사전순으로 낮은 직원의 이름, 부서코드 조회
SELECT emp_name, dept_code
FROM employee
WHERE dept_code <= 'D2'; -- 문자열도 대소 비교가능!
-- 검색할 컬럼의 조건을 설정하여 행 결정, 이때 조건은 다중 논리 조건 활용 가능
-- - 급여가 4000000보다 많은 직원 이름과 급여 조회
SELECT emp_name, salary
FROM employee
WHERE salary > 4000000;
-- - 입사일이 2020년 이후인 직원
SELECT emp_name, salary, hire_date
FROM employee
WHERE hire_date > '2020-01-01';
-- 여러 개 조건 작성 시 AND/OR 사용 → 연산자 우선순위 존재!!!
-- - 부서코드가 D6이고 급여를 2000000보다 많이 받는 직원의 이름, 부서코드, 급여 조회
SELECT emp_name, dept_code, salary
FROM employee
WHERE dept_code = 'D6' AND salary > 2000000;
-- - 부서코드가 D6이거나 급여를 2000000보다 많이 받는 직원의 이름, 부서코드, 급여 조회
SELECT emp_name, dept_code, salary
FROM employee
WHERE dept_code = 'D6' OR salary > 2000000;
여러 개의 제한 조건 결과를 하나의 논리 결과로 만들어 주는 연산자
| 연산자 | 설명 |
|---|---|
| AND | 여러 조건이 동시에 TRUE일 경우에만 TRUE값 반환 |
| OR | 여러 조건들 중에 어느 하나의 조건만 TRUE이면 TRUE값 반환 |
| NOT | 조건에 대한 반대 값으로 반환(NULL 제외) |
※ 연산자 우선순위는 NOT > AND > OR
| TRUE | FALSE | NULL | |
|---|---|---|---|
| TRUE | TRUE | FALSE | NULL |
| FALSE | FALSE | FALSE | FALSE |
| NULL | NULL | FALSE | NULL |
| TRUE | FALSE | NULL | |
|---|---|---|---|
| TRUE | TRUE | TRUE | TRUE |
| FALSE | TRUE | FALSE | NULL |
| NULL | TRUE | NULL | NULL |
표현식 사이의 관계를 비교하기 위해 사용 결과는 논리 결과(TRUE/FALSE/NULL) 중 하나가 된다.
동적 타이핑이 가능해서 비교 연산 시 자동으로 타입을 맞춰 주지만 완벽하진 않다.
비교 연산자 사용 시 숫자, 문자, 날짜 type까지 대소 비교가 가능하다!
| 연산자 | 의미 | 예시 | 설명 |
|---|---|---|---|
= | 같음 | age = 30 | age가 30인 행 |
!= 또는 <> | 같지 않음 | city != 'Seoul' | 서울이 아닌 도시 |
> | 보다 큼 | score > 80 | 점수가 80 초과 |
< | 보다 작음 | price < 10000 | 가격이 1만원 미만 |
>= | 크거나 같음 | age >= 18 | 성인 이상 |
<= | 작거나 같음 | discount <= 20 | 20% 이하 할인 |
IS NULL | NULL 여부 | email IS NULL | 이메일이 없는 경우 |
IS NOT NULL | NULL 아님 | phone IS NOT NULL | 전화번호 있는 경우 |
BETWEEN A AND B | 범위 내 포함 | score BETWEEN 70 AND 90 | 70 이상 90 이하 |
IN (...) | 목록 안에 있음 | grade IN ('A', 'B') | A 또는 B 등급 |
NOT IN (...) | 목록에 없음 | id NOT IN (1, 2, 3) | ID가 1, 2, 3이 아닌 경우 |
LIKE | 패턴 일치 | name LIKE 'abc%' | abc로 시작하는 이름 |
ILIKE (PostgreSQL 전용) | 패턴 일치 (대소문자 구분X) | name ILIKE 'abc%' | ABC 또는 abc로 시작하는 이름 |
NOT LIKE | 패턴 불일치 | email NOT LIKE '%.com' | .com으로 끝나지 않는 이메일 |
비교하려는 값의 범위를 표현 할 수 있는 문법
만일 포함되면 TRUE를 리턴 하는 연산자 상한 값과 하한 값의 경계도 포함됨
SELECT emp_name, salary
FROM employee
WHERE salary >= 3500000 AND salary <= 6000000;
-- 또는
SELECT emp_name, salary
FROM employee
WHERE salary BETWEEN 3500000 AND 6000000;
비교하려는 값이 지정한 특정 패턴을 만족하면 TRUE를 리턴 하는 연산자
'%'와 '_'를 와일드 카드로 사용, 와일드 카드는 문자열 앞과 뒤에 표기 될 수 있음
Ex) '홍%', '%길동', '%길%', '_길동', '홍__', '_길_'
SELECT emp_name, salary
FROM employee
WHERE emp_name LIKE ‘%동훈’;
SELECT emp_name, phone
FROM employee
WHERE phone LIKE ‘___7%’;
와일드 카드 문자와 패턴의 특수문자가 동일한 경우 어떤 것을 패턴으로 결정하는지 구분하지 못하기 때문에 데이터로 처리할 와일드 카드 문자 패턴 기호 앞에 임의의 특수문자를 사용하고 ESCAPE OPTION으로 등록하여 처리
SELECT emp_name, email
FROM employee
WHERE email LIKE '__ _#_%' ESCAPE '#';
LIKE절의 부정표현으로 'NOT' 키워드를 활용할 수 있음
SELECT emp_id, emp_name, email
FROM employee
WHERE emp_name NOT LIKE ‘이%’;
-- 또는
SELECT emp_id, emp_name, email
FROM employee
WHERE NOT emp_name LIKE ‘이%’;
값의 NULL 여부를 확인 하는 유일한 연산자, = NULL은 잘못된 표현이다.
NULL은 데이터 공백을 의미하며, 빈문자열과 0과 다르다.
SELECT emp_name, manager_id, dept_code
FROM employee
WHERE manager_id IS NULL AND dept_code IS NULL;
SELECT emp_name, bonus, dept_code
FROM employee
WHERE dept_code IS NULL AND bonus IS NOT NULL;
IN은 비교하려는 값 목록(다수)에 일치하는 값이 있으면 결과를 반환하는 연산자
NOT IN은 포함하지 않는 결과를 반환 할 때 활용하는 연산자
→ 생각보다 매우 중요한 연산자로 상품의 카테고리 체크 할 때 자주 사용
SELECT emp_name, dept_code, salary
FROM employee
WHERE dept_code IN (‘D6’, ‘D8’);
-- 또는
SELECT emp_name, dept_code, salary
FROM employee
WHERE dept_code = ‘D6’ OR dept_code = ‘D8’;
| 우선순위 | 연산자 |
|---|---|
| 0 | (괄호) |
| 1 | 산술 연산자 +-*/% |
| 2 | 연결 연산자 |
| 3 | 비교 연산자 = > |
| 4 | IS NULL / IS NOT NULL , LIKE , IN / NOT IN |
| 5 | BETWEEN AND / NOT BETWEEN AND |
| 6 | 논리 연산자 – NOT |
| 7 | 논리 연산자 – AND |
| 8 | 논리연산자 – OR |
SELECT emp_name, salary, job_code
FROM employee
WHERE job_code = ‘J7’ OR job_code = ‘J2’ AND salary > 2000000; -- 잘못된 쿼리
-- * 연산자 우선 순위에 의해서 AND가 먼저 실행됨
-- J2직급의 급여 2000000 이상 받는 직원이거나 J7직급인 직원이라는 의미
SELECT emp_name, salary, job_code
FROM employee
WHERE (job_code = ‘J7’ OR job_code = ‘J2’) AND salary > 2000000;
-- * 우선순위를 고려하여 OR가 먼저 처리 되도록 ( )를 이용해 우선 순위 변경
-- J7 직급이거나 J2직급인 직원들 중 급여 2000000 이상 받는 직원이라는 의미
SELECT한 컬럼에 대해 정렬을 할 때 작성하는 구문으로 SELECT 구문의 가장 마지막에 작성하며 실행 순서 역시 가장 마지막에 수행됨 (우선순위가 가장 낮음)
LIMIT절은 행의 개수를 제한하는 문장으로 ORDER BY 보다 우선순위가 낮다.
OFFSET은 LIMIT절 수행 시 OFFSET(넘어갈) 개수를 지정하는 문장이다.
SELECT 컬럼 명 \[, 컬럼명, …]
FROM 테이블 명
WHERE 조건식
ORDER BY 컬럼명 | 별칭 | 컬럼 순번 정렬방식 [NULLS FIRST | LAST];
LIMIT 값, OFFSET 값
/*
* 정렬 방식
- ASC : 오름차순(Ascending)
- DESC : 내림차순(Descending)
*/
SELECT * FROM employee ORDER BY emp_id ASC; OR DESC; -- 생략 시 ASC 정렬
SELECT * FROM employee ORDER BY emp_name ASC; OR DESC;
SELECT emp_name, dept_code FROM employee
ORDER BY dept_code ASC, emp_name ASC;
LIMIT 절은 MySQL에서 행수를 제어하기 위한 전용 문법으로 ANSI 비표준 문법
순서 절(ORDER BY)과 함께 사용하면 RANK를 제어하는 구문으로 사용가능
ex) 가입순으로 5명, 이름 사전순으로 5명, 나이가 많은 5명 ….
SELECT * FROM employee LIMIT 5;
SELECT emp_id, emp_name FROM employee
ORDER BY emp_name
OFFSET 5;
LIMIT + OFFSET + ORDER BY를 결합하여 Paging 처리를 수행 할 수 있다.
LIMIT는 출력되는 개수, OFFSET은 0(처음) 부터 넘어 갈 개수로 제어 할 수 있다. (OFFSET은 생략 가능)
Ex) 게시판의 페이징(Paging) 10개씩 처리 시 1page는 LIMIT 10, OFFSET 0, 2page는 LIMIT 10, OFFSET 10, 3page는 LIMIT 10, OFFSET 20 ….
SELECT * FROM employee ORDER BY emp_id LIMIT 5 OFFSET 0;
SELECT * FROM employee ORDER BY emp_id LIMIT 5 OFFSET 5;
SELECT * FROM employee ORDER BY emp_id LIMIT 5 OFFSET 10;