🔖

SQL 1つのカラムに「カンマ区切り値」を入れる際の問題点と解決策

2025/01/14に公開

はじめに

最近、オライリー・ジャパンの「SQLアンチパターン」という本を読みました。

本書から学んだ知識をベースに、「1つのカラムにカンマ区切りの値を保存する」というアンチパターンについて、私なりの実例を交えながら解説したいと思います。

なお、本記事の実装例やデメリットの説明は、書籍の内容をそのまま転記したものではなく、私が再解釈した内容となっています。

参考著書

オライリー・ジャパン「SQLアンチパターン」
https://www.oreilly.co.jp/books/9784873115894/

問題のある実装例

以下のような書籍管理テーブルがあるとします。

CREATE TABLE books (
    id INTEGER PRIMARY KEY,
    title VARCHAR(255),
    tags VARCHAR(255)  -- カンマ区切りでタグを保存
);

INSERT INTO books (title, tags) VALUES
('サバイバルTypeScript', 'TypeScript, 入門');

デメリット

  1. 検索が難しい

    • LIKE演算子を使う必要があり、パフォーマンスが悪い
      -- 'TypeScript'タグを含む書籍を検索
      SELECT * FROM books WHERE tags LIKE '%TypeScript%';
      
    • インデックスが効果的に使えない
      • このように検索文字列の前にワイルドカード(%)がある場合、インデックスが効果的に使えません。
      • これは、インデックスは先頭から順に検索を行う仕組みのため、文字列の途中や末尾からの検索では活用できないためです。
      • そのため、タグを検索する度に全文検索が発生し、データ量が増えるほど検索が遅くなります。
  2. データの整合性が保ちづらい

    • タグ名が不統一になりやすい(「TypeScript」と「typescript」など)
  3. 文字列の長さに制限がある

    • VARCHAR(255)のような固定長のため、格納できるタグの数に制限がある
    • タグが増えていくと、制限に達して新しいタグが追加できなくなる可能性がある
  4. 更新が大変

    • 特定のタグだけを削除したい場合、文字列操作が必要になる
    • タグの位置によって更新のロジックが変わる(先頭、中間、末尾)
    • カンマの扱いも考慮が必要(余分なカンマが残ったり、カンマの数が不適切になったり)

解決策:交差テーブルの作成

以下のように、多対多の関係を表現する設計に変更します。

CREATE TABLE books (
    id INTEGER PRIMARY KEY,
    title VARCHAR(255)
);

CREATE TABLE tags (
    id INTEGER PRIMARY KEY,
    name VARCHAR(50)
);

CREATE TABLE book_tags (
    book_id INTEGER,
    tag_id INTEGER,
    PRIMARY KEY (book_id, tag_id),
    FOREIGN KEY (book_id) REFERENCES books(id),
    FOREIGN KEY (tag_id) REFERENCES tags(id)
);

この設計により、検索が容易になり、データの整合性も保つことができようになります。

まとめ

これまで「1つのカラムにカンマ区切りの値を保存するのは良くない」という漠然とした認識は持っていましたが、今回SQLアンチパターンを読んで自分で噛み砕いていく中で、なぜ良くないのかを具体的に理解することができました。

インデックスが効かない理由や、文字列長の制限や更新の大変さによる実用上の問題など、技術的な背景を知ることで、より良いデータベース設計の重要性を実感することができました。

Discussion