[멋사 클라우드 5기] Day 11 - DBMS 기초(2), DQL

2026. 2. 5. 00:51·Learning Log

오늘은 Java 없이... 무호흡 DQL 개념정리 및 실습을 진행했다.

과목이 바뀌니까 환기도 되고 좋은 것 같다.

기억이 날라가기 전에 기록으로 정리해본다. 


관계형 데이터베이스(RDBMS)란?

관계형 데이터베이스는
엑셀 표(Table)를 아주 엄격한 규칙으로 관리하는 데이터베이스라고 생각하면 이해하기 쉽다.

  • 데이터는 항상 표 형태로 저장되고
  • 각 표는 명확한 구조(스키마)를 가지며
  • 테이블 간의 관계(Relation)를 통해 데이터를 연결한다

이 “엄격함” 덕분에
데이터의 무결성과 일관성을 강하게 보장할 수 있다.


관계형 데이터베이스의 주요 특징

1. 데이터 무결성 (Integrity)

데이터가 깨지지 않고, 논리적으로 말이 되는 상태를 유지하는 것

  • DB 차원에서 강하게 보장됨
  • 잘못된 데이터 자체가 들어오지 못하게 막는 규칙

예시:

  • 주문 테이블의 member_id는
    반드시 회원 테이블에 실제로 존재하는 회원 ID여야 한다
  • 존재하지 않는 회원으로 주문을 만들 수 없음

이런 제약이 있어야 비즈니스 로직 자체가 성립한다.

 

2. 데이터 일관성 (Consistency)

어디에서 조회하든, 같은 데이터는 항상 같은 값을 가져야 함

  • 시스템 전체에서 데이터가 논리적으로 모순되지 않는 상태
  • DB 제약 + 애플리케이션 로직이 함께 보장

예시:

  • 계좌 잔액이 10,000원
  • 3,000원 출금
  • 이후 모든 화면 / 조회 지점에서 7,000원으로 보여야 함

저장된 규칙과 제약 조건이
항상 지켜지는 상태가 바로 데이터 일관성이다.

 

3. 정형화된 데이터 구조 (Schema)

  • 테이블의 컬럼 구조가 미리 정해져 있음
  • 각 컬럼은 타입과 제약 조건을 가짐
id INT
name VARCHAR(50)
created_at DATETIME
  • 새로운 컬럼을 추가하거나 구조를 바꾸려면
    스키마 변경 작업이 필요하다

👉 대신, 구조가 명확해서
데이터 해석이 일관되고 안정적이다.

 

4. SQL 지원

  • 관계형 DB는 SQL(Structured Query Language)을 사용한다
  • 데이터 조회(DQL), 삽입/수정(DML), 구조 변경(DDL)을
    명확한 문법으로 처리

👉 오늘 실습의 중심이 바로 이 SQL(DQL)

 

5. 보안과 권한 제어

  • 사용자별 접근 권한 제어 가능
  • 읽기 / 쓰기 / 수정 권한을 세밀하게 분리

금융, 결제, ERP 같은
신뢰성이 중요한 시스템에서 필수적인 요소


NoSQL 데이터베이스란?

NoSQL은
형식에 덜 얽매이고, 빠르고 유연하게 저장하는 데이터베이스다.

관계형 DB가 “엄격한 표”라면,
NoSQL은 “상황에 맞게 구조가 달라도 되는 저장소”에 가깝다.


NoSQL의 주요 특징

1. 비정형 / 유연한 데이터 구조

  • 미리 정해진 테이블 구조가 필수는 아님
  • 데이터마다 필드 수가 달라도 허용
{ "id": 1, "message": "hello" }
{ "id": 2, "message": "hi", "emoji": "😊" }

빠른 개발과 변경에 유리

 

2. 분산 처리 환경

  • 한 대의 서버가 아닌 여러 서버가 나눠서 처리
  • 일부 서버 장애가 나도 전체 서비스는 계속 동작
  •  

3. 높은 가용성

  • 장애에 강함
  • 일부 노드가 죽어도 다른 노드가 요청 처리

👉 실시간 서비스에 적합

 

4. 수평적 확장성

  • 서버를 “더 좋은 서버”로 바꾸는 대신(수직적 확장)
  • 서버를 여러 대로 늘리는 방식
트래픽 증가 → 서버 한 대 추가

👉 NoSQL은 설계 자체가
확장성을 전제로 만들어짐


관계형 DB vs NoSQL 정리

구분관계형 DBNoSQL

데이터 구조 엄격한 표 구조 자유로운 구조
무결성 / 일관성 매우 강함 상대적으로 약함
확장 방식 수직 확장 (서버 성능 ↑) 수평 확장 (서버 수 ↑)
트랜잭션 강력함 제한적
대표 사용처 금융, 결제, ERP 로그, 채팅, SNS, 실시간 데이터

 


2-0. DQL (Data Query Language)

데이터 검색 기능에 사용하는 SQL

2-1. NULL은 “값이 없다” ≠ “비교 가능하다”

❌ 잘못된 비교

WHERE comm = NULL;
  • NULL은 값이 아니라 상태
  • 어떤 연산에서도 = 비교가 성립하지 않음

⭕ 올바른 비교

WHERE comm IS NULL;
WHERE comm IS NOT NULL;

📌 NULL은 항상 IS / IS NOT으로 비교


2-2. NULL이 연산에 미치는 영향 (연봉 계산)

sal * 12 + comm
  • comm이 NULL이면 결과 전체가 NULL
  • 연산 자체가 무효 처리됨

해결 방법 1️⃣ IFNULL (MySQL)

sal * 12 + IFNULL(comm, 0)

해결 방법 2️⃣ COALESCE (표준 SQL, 권장)

sal * 12 + COALESCE(comm, 0)

📌 COALESCE(a, b, c, …)
→ 왼쪽부터 순서대로 NULL 아닌 첫 값 반환


2-3. IN 연산자 + NULL의 함정 ⚠️

기본 IN

WHERE comm IN (300, 500, 1400);

NOT IN의 문제점

WHERE comm NOT IN (300, 500, 1400);
  • comm이 NULL이면 결과에서 제외됨
  • “조건에 안 걸리는 게 아니라, 비교 자체가 안 됨”

NULL까지 포함하고 싶다면

WHERE comm NOT IN (300, 500, 1400)
   OR comm IS NULL;

📌 NOT IN 사용할 때는 항상 NULL 존재 여부를 의식해야 한다


2-4. BETWEEN은 “이상 / 이하” 포함이다

WHERE sal BETWEEN 2975 AND 3000;

= 👇 완전히 동일

WHERE sal >= 2975 AND sal <= 3000;

📌 날짜에도 동일하게 적용됨

WHERE hiredate BETWEEN '1981-01-01' AND '1981-12-31';

2-5. LIKE 패턴은 자리 수를 정확히 구분한다

패턴의미

M% M으로 시작
M_ M + 딱 한 글자
_M% 두 번째 글자가 M
%M% M 포함
WHERE ename LIKE 'M_';

→ 두 글자 이름만 검색


2-6. 대소문자 구분: BINARY 키워드 (중요)

WHERE ename = 'smith';
  • MySQL 기본 설정에서는 대소문자 구분 안 됨

대소문자 구분 강제

WHERE BINARY ename = 'SMITH';

📌 BINARY는 문자열을 바이트 단위로 비교

  • 'SMITH' ≠ 'smith'

왜 이런 일이 생길까?

SHOW VARIABLES LIKE 'lower_case_table_names';
  • OS / 설정에 따라 문자열 비교 방식이 달라짐
  • 그래서 대소문자 민감한 비교는 BINARY로 명시하는 게 안전

2-7. ORDER BY에서 헷갈리는 디테일들

ORDER BY는 SELECT 이후에 실행된다

SELECT empno AS 사번
FROM emp
ORDER BY 사번 DESC;

📌 별칭(alias) 사용 가능


NULL 정렬 위치

ORDER BY comm ASC;  -- NULL 먼저
ORDER BY comm DESC; -- NULL 나중

명시적으로 제어하기

ORDER BY (comm IS NULL) ASC, comm ASC;
  • (comm IS NULL) → NULL이면 1, 아니면 0
  • 결과적으로 NULL을 뒤로 보냄

ORDER BY 컬럼 인덱스 (비권장)

ORDER BY 3 ASC, 2 DESC;
  • 동작은 하지만 가독성 최악
  • 실무에선 거의 안 씀

2-8. AND / OR 연산자 우선순위 ⚠️

기본 우선순위

AND > OR

헷갈리기 쉬운 예제

WHERE deptno = 10 OR deptno = 20 AND job = 'CLERK';

👉 실제 해석:

deptno = 10
OR (deptno = 20 AND job = 'CLERK')

의도가 이거라면?

WHERE (deptno = 10 OR deptno = 20)
  AND job = 'CLERK';

📌 OR가 있으면 무조건 괄호부터 고민


3-0. 단일행 함수 vs 그룹 함수

  • 단일행 함수: 입력 행 1개 → 출력 1개
    예) ABS(), ROUND(), SUBSTRING(), DATE_ADD(), IF(), CONCAT()
  • 그룹 함수(집계 함수): 여러 행 → 결과 1개(또는 그룹별 1개)
    예) COUNT(), SUM(), AVG(), MAX(), MIN()

3-1. 숫자 함수

ROUND vs TRUNCATE(버림)

SELECT ROUND(12.345, 2);      -- 12.35 (반올림)
SELECT TRUNCATE(12.345, 2);   -- 12.34 (버림)
  • ROUND(x, -1) : 1의 자리에서 반올림 → 10단위로
  • TRUNCATE(x, -1) : 1의 자리 버림 → 10단위로

MOD / % (홀짝, 주기, 그룹 분기)

WHERE MOD(empno, 2) = 1;
  • 홀짝 / “N개 단위로 묶기” 할 때 자주 씀.

3-2. 문자열 함수

LENGTH vs CHAR_LENGTH (한글/멀티바이트 주의)

SELECT LENGTH('가나다');      -- 바이트 길이(환경에 따라 9 등)
SELECT CHAR_LENGTH('가나다'); -- 문자 개수(3)
  • LENGTH는 바이트 기준
  • CHAR_LENGTH는 문자 수 기준

📌 “글자 수 제한” 같은 로직이면 CHAR_LENGTH가 더 안전.

 

SUBSTRING으로 날짜에서 월 뽑기 vs 날짜 함수

WHERE SUBSTRING(hiredate, 6, 2) = '02';

날짜 함수로 더 안정적으로 바꾼다면

WHERE MONTH(hiredate) = 2;

 

 

TRIM은 공백(space) 중심

  • TRIM()은 보통 앞뒤 공백 제거,
  • 탭/개행까지 완벽히 제거하려면 별도 처리(예: REPLACE)가 필요

3-3. 날짜 함수: NOW vs SYSDATE 차이

NOW()

  • 쿼리 시작 시점의 시간을 고정해서 씀
  • created_at, updated_at, 로그 기록 등에 안정적
SELECT NOW(), SLEEP(2), NOW(); -- NOW 값이 동일하게 나옴

 

SYSDATE()

  • 함수 호출 시점의 현재 시간
  • 서버 상태 체크 같은 “진짜 지금”을 볼 때 사용
SELECT SYSDATE(), SLEEP(2), SYSDATE(); -- 값이 달라짐

📌 “같은 쿼리에서 시간이 바뀌면 안 된다” → NOW
📌 “호출 순간의 현재시간이 중요” → SYSDATE


3-4. Date vs Datetime: ‘하루 차이’ 함정

SELECT DATEDIFF('2026-02-05 00:00:00', '2026-02-04 23:59:59'); -- 1
  • DATEDIFF는 시간을 무시하고 날짜 단위로 계산

시간까지 포함해서 정확히 계산하려면:

SELECT TIMESTAMPDIFF(DAY, '2026-02-04 00:00:00', '2026-02-04 23:59:59'); -- 0

📌 날짜 필터링도 이 이유로 “범위 조건”이 안전함:

WHERE hiredate >= '2026-02-04' AND hiredate < '2026-02-05'

3-5. 형변환: MySQL의 “암묵적 변환”은 편하지만 위험

SELECT '123abc' + 1; -- 124
SELECT 'abc123' + 1; -- 1 (앞이 숫자가 아니면 0 취급)

암묵적 변환에 기대면 잘못된 값이 나올 수 있다.
→ CAST/CONVERT로 의도를 명시하는 게 안전.

 

CAST의 핵심 용도

  • 문자열 → 숫자(계산)
  • 문자열 → 날짜(필터)
  • 숫자 → 문자열(출력)
SELECT CAST('123' AS UNSIGNED);
SELECT CAST('20260204' AS DATE);
SELECT CAST(NOW() AS CHAR);

 

DATE_FORMAT / STR_TO_DATE

  • DATE_FORMAT: 날짜 → 문자열(표시 목적)
  • STR_TO_DATE: 문자열 → 날짜(파싱 목적)

3-6. 제어 흐름: IF / COALESCE

SELECT IF(sal >= 2500, '고급여', '저급여') AS 등급
FROM emp;
  • 간단한 라벨링/파생컬럼에 많이 사용

COALESCE는 “NULL 보정”에서 사실상 필수:

COALESCE(comm, 0)

3-7. 문자열 조작: CONCAT / REPLACE

SELECT CONCAT(ename, '(', job, ')') FROM emp;
SELECT REPLACE(job, 'MAN', 'PERSON') FROM emp;

📌 출력 포맷 만들 때 유용 


3-8. GROUP BY + HAVING: 실행 순서가 핵심

실행 순서:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

WHERE vs HAVING

  • WHERE: 그룹 만들기 전 행(row) 필터
  • HAVING: 그룹 만든 후 그룹(집계 결과) 필터

✅ 예: “부서별 평균 급여가 2000 이상”은 HAVING

SELECT deptno, AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal) >= 2000;

 

COUNT(comm)가 4가 되는 이유 (NULL 자동 제외)

SELECT COUNT(comm) FROM emp; -- NULL 제외
  • COUNT(*) : 행 수(전부)
  • COUNT(col) : NULL 제외한 개수

3-9. alias(별칭) + ORDER BY: 백틱을 사용하자

SELECT deptno, SUM(sal), AVG(sal) AS `평균급여`
FROM emp
GROUP BY deptno
ORDER BY `평균급여` ASC;

-- ORDER BY '평균급여' ASC; -> 정상동작 X
-- ORDER BY 평균급여 ASC; -> 정상동작 O (비권장)
-- ORDER BY `평균급여` ASC; --> 정상동작 O + 공백처리 O (권장)

📌 별칭에 공백/한글 넣으면 백틱이 필요해지니까, 실무에선 보통 avg_sal처럼 씀.

'Learning Log' 카테고리의 다른 글

[멋사 클라우드 5기] Day 13 - DML, DDL, DCL, TCL  (0) 2026.02.08
[멋사 클라우드 5기] Day 12 - Join, Subquery, Union  (0) 2026.02.06
[멋사 클라우드 5기] Day 10 - 객체 다루기, DBMS 기초(1)  (0) 2026.02.04
[멋사 클라우드 5기] Day 9 - Enum 활용, BigNumber, Lombok, 객체 설계  (1) 2026.02.03
[멋사 클라우드 5기] Day 8 - 입출력, 직렬화, 스레드, Enum  (0) 2026.02.02
'Learning Log' 카테고리의 다른 글
  • [멋사 클라우드 5기] Day 13 - DML, DDL, DCL, TCL
  • [멋사 클라우드 5기] Day 12 - Join, Subquery, Union
  • [멋사 클라우드 5기] Day 10 - 객체 다루기, DBMS 기초(1)
  • [멋사 클라우드 5기] Day 9 - Enum 활용, BigNumber, Lombok, 객체 설계
allluck777
allluck777
allluck777
    • 분류 전체보기 (44) N
      • AWS (0)
      • Network (0)
      • Linux (0)
      • Docker (0)
      • Project (4)
        • CloudNote (4)
      • Learning Log (36) N
      • Lecture (3)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (3)
  • 전체
    오늘
    어제
  • hELLO· Designed By정상우.v4.10.6
allluck777
[멋사 클라우드 5기] Day 11 - DBMS 기초(2), DQL
상단으로

티스토리툴바