블로그 카테고리는 어떻게 만들면 좋을까
수정일: 2025. 9. 27.
개요
이번 글에서는 블로그의 카테고리를 어떻게 만들면 좋을지 고민해보겠습니다. 카테고리를 담을 TABLE의 설계에 대해 알아보겠습니다.
- 들어가며
- 카테고리에 대해
- SQL 스키마 예제
- 가장 간단한 트리 구조
- 가장 간단한데 문자열 버전
- CTE를 통한 조회
- 마치며
들어가며
보통 블로그는 카테고리를 제공하는 경우가 많습니다. 카테고리는 한글로는 범주로 번역할 수 있다고 합니다. 동일한 성질을 가진 부류나 범위를 가리키며 블로그에서의 카테고리는 포스트를 구분하고 정리하는 수단으로 사용됩니다.
예를 들어 여행 관련 포스트와 맛집 관련 포스트는 서로 다른 카테고리로 분류하는게 좋을 수 있습니다. 맛집 카테고리는 맛집에 대한 내용이 주를 이루고, 여행 관련 카테고리는 여행 관련 내용으로 모아져 있다면, 각 관심사에 따라 모아볼 수 있는 장점이 있기 때문입니다.
카테고리에 대해
카테고리는 계층 구조를 가지는 경우가 많습니다. 예를 들어, 한국 -> 서울 -> 용산처럼 범위를 좁혀가는 형태가 일반적으로 사용됩니다. 점점 좁혀갈 수록 수가 줄어들며 원하는 데이터에 접근할 확률이 올라가게 됩니다.
SQL에서는 어떻게 이 구조를 표현할까
이 구조는 대표적인 트리 구조를 통해 구현할 수 있습니다. SQL로도 충분히 트리 구조를 구현할 수 있는데요,
가장 단순한 예시부터 확인해보겠습니다. 저희가 알던 그 트리 구조와 매우 비슷합니다. 자식의 경우 부모를 바로 찾아갈 수 있으나, 부모는 자식을 찾기 위해 자기 테이블을 재귀 순회하며 풀스캔을 해야합니다. 하지만 트리 구조를 매우 단순하게 구현할 수 있습니다.
가장 간단한 트리 구조
-- 기본 방법: 인접 목록 모델(Adjacency List Model)
-- 행의 고유값이 INTEGER이고, 부모-자식 관계도 INTEGER로만 구성되어 명시적이지 못함
CREATE TABLE categories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
parent_id INTEGER,
FOREIGN KEY (parent_id) REFERENCES categories(id)
);
CREATE INDEX idx_parenet_id ON categories(parent_id);
다만, 데이터를 밀어 넣을 때, 숫자로 부모 자식 관계를 표현하면 파악하기 난해할 수 있습니다. 이를 위해 숫자를 텍스트로 변경하게 되면 아래와 같이 변형이 가능합니다.
가장 간단한 트리 문자열 구조
-- 텍스트 기반 구조
CREATE TABLE categories_text_ver (
slug TEXT PRIMARY KEY,
name TEXT NOT NULL,
parent_slug TEXT,
FOREIGN KEY (parent_slug) REFERENCES categories_text_ver(slug)
);
CREATE INDEX idx_parent_slug_ ON categories_text_ver(parent_slug);
차이는 slug를 PK로, 타입을 TEXT로 변경한 점입니다.
CTE를 통한 조회
CTE를 통해 아래와 같이 조회할 수 있습니다.
SELECT
문으로 루트 노드들을 찾고 이를 level 0으로 둡니다.
다음 그 결과들을 뒤이어 올 쿼리 결과와 UNION ALL
하여 합칩니다.
WITH RECURSIVE tree AS (
SELECT slug, name, parent_slug, 0 as level -- 루트 노드를 찾아 0이라는 라벨을 붙이고 이를 레벨이라 부름
FROM categories_text_ver WHERE parent_slug IS NULL -- 부모가 NULL인 경우 루트임
UNION ALL -- 위에서 찾은 것 결과를 아래의 결과와 합칠 것 이항연산
SELECT c.slug, c.name, c.parent_slug, t.level + 1 -- 위에서 표현한 tree 보다 한 depth 더 들어갔기 때문에 +1 해줌
FROM categories_text_ver c JOIN tree t ON c.parent_slug = t.slug
-- tree에 있는 노드의 slug가
-- categories_text_ver의 parent_slug와 같은 것을 찾음
-- 즉, "이미 찾은 노드들의 자식들"을 찾는 것
)
SELECT slug, name, level FROM tree ORDER BY level, name; -- 위 결과들 중에 이 것들을 뽑음
마치며
실무에서는 더 다양한 요구사항들이 있으며, 복잡하고 다양한 카테고리들이 많습니다.