C++: プロジェクト:簡易データベース

最終更新:2026-08-31

レッスン51では、住所録システムを作りました。

ここでは、総合実践プロジェクト——簡易データベースを作ります。

このプロジェクトはC++の知識を統合し、学習成果を示します。


1. プロジェクト概要

(1) 1.1 機能一覧

機能 説明
CREATE TABLE テーブル作成
INSERT データ挿入
SELECT データ検索
WHERE 条件指定
保存 ファイルへ保存
トランザクション ACIDトランザクション

(2) 1.2 設計方針

プロジェクトをシンプルにするため、以下の制約を設けます:




2. データ構造

(1) 2.1 定義

▶ サンプル 2:コード例(難易度 ⭐)

TEXT 📖 参照専用
#include <iostream>
#include <string>
#include <variant>
#include <vector>

// 列定義
struct Column {
    std::string name;
    enum Type { INT, STRING } type;
};

// 値(variant)
using Value = std::variant<int, std::string>;

// 行(値の配列)
using Row = std::vector<Value>;

// テーブル
class Table {
private:
    std::string name;
    std::vector<Column> columns;
    std::vector<Row> rows;

public:
    Table(const std::string& name, const std::vector<Column>& columns)
        : name(name), columns(columns) {}
    
    // 挿入
    void insert(const Row& row) {
        if (row.size() != columns.size()) {
            std::cerr << "列数が一致しません..." << std::endl;
            return;
        }
        rows.push_back(row);
    }
    
    // 全件検索
    std::vector<Row> select() {
        return rows;
    }
    
    // 構造表示
    void describe() const {
        std::cout << "テーブル:" << name << std::endl;
        std::cout << "列:" << std::endl;
        for (const auto& col : columns) {
            std::cout << "  " << col.name << " (";
            if (col.type == Column::INT) {
                std::cout << "INT";
            } else {
                std::cout << "STRING";
            }
            std::cout << ")" << std::endl;
        }
    }
};



3. WHERE条件の実装

(1) 3.1 述語の使用

CPP
// 条件関数(WHERE)
using Predicate = std::function<bool(const Row&)>;

// 条件検索
std::vector<Row> selectWhere(Predicate pred) {
    std::vector<Row> result;
    for (const auto& row : rows) {
        if (pred(row)) {
            result.push_back(row);
        }
    }
    return result;
}

// 使用例:age > 18
auto predicate = [](const Row& row) {
    int age = std::get<int>(row[1]); // 2列目がage
    return age > 18;
};

auto result = table.selectWhere(predicate);



4. インデックスの実装

(1) 4.1 インデックス

TEXT 📖 参照専用
#include <map>

// インデックス(int型)
class Index {
private:
    std::map<int, std::vector<int>> index; // 値 -> 行番号

public:
    void build(const std::vector<Row>& rows, int colIndex) {
        index.clear();
        for (int i = 0; i < rows.size(); i++) {
            int key = std::get<int>(rows[i][colIndex]);
            index[key].push_back(i);
        }
    }
    
    std::vector<int> lookup(int key) {
        auto it = index.find(key);
        if (it != index.end()) {
            return it->second;
        }
        return {};
    }
};



5. トランザクションの実装

(1) 5.1 トランザクション

CPP
#include <stack>

class Transaction {
private:
    std::stack<std::vector<Row>> undoStack;

public:
    // 開始(スナップショット)
    void begin(Table& table) {
        undoStack.push(table.rows);
    }
    
    // コミット(確定)
    void commit() {
        while (!undoStack.empty()) {
            undoStack.pop();
        }
    }
    
    // ロールバック(取り消し)
    void rollback(Table& table) {
        if (!undoStack.empty()) {
            table.rows = undoStack.top();
            undoStack.pop();
        }
    }
};



6. 使用例

▶ サンプル 1:データベースの使用(難易度 ⭐⭐⭐)

TEXT 📖 参照専用
int main() {
    // テーブル作成
    Table t("users", {{"name", Column::STRING}, {"age", Column::INT}});
    
    // データ挿入
    t.insert({"田中", 25});
    t.insert({"佐藤", 30});
    t.insert({"鈴木", 20});
    
    // 全件検索
    auto rows = t.select();
    std::cout << "検索結果:" << std::endl;
    for (const auto& row : rows) {
        std::cout << std::get<std::string>(row[0]) << ", "
                  << std::get<int>(row[1]) << std::endl;
    }
    
    return 0;
}



7. 拡張機能

(1) 7.1 機能一覧

機能 難易度 説明
DELETE ⭐⭐ ファイル保存
JOIN ⭐⭐⭐⭐ テーブル結合
SQLパーサー ⭐⭐⭐⭐⭐ SQL文法解析
並行性制御 ⭐⭐⭐⭐ マルチスレッド対応



8. 練習問題

(1) 初級(難易度 ⭐⭐)

データベースに DELETE 機能を追加。

(2) 中級(難易度 ⭐⭐⭐)

データベースに UPDATE 機能を追加。

(3) 上級(難易度 ⭐⭐⭐⭐)

簡易SQLパーサーを実装し、SELECT * FROM table WHERE age > 18 を解析。



▶ サンプル 3:簡易テーブルクエリ(難易度 ⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <string>
#include <functional>

struct Row {
    std::string name;
    int age;
};

void queryWhere(std::vector<Row>& rows, std::function<bool(const Row&)> pred) {
    for (const auto& row : rows) {
        if (pred(row)) {
            std::cout << row.name << ", " << row.age << std::endl;
        }
    }
}

int main() {
    std::vector<Row> users = {
        {"田中", 25},
        {"佐藤", 17},
        {"鈴木", 30},
        {"山田", 16}
    };

    std::cout << "成年人 (age >= 18):" << std::endl;
    queryWhere(users, [](const Row& r) { return r.age >= 18; });

    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
成年人 (age >= 18):
田中, 25
鈴木, 30

❓ よくある質問

Q:データベースプロジェクトで最も重要なことは? A:まず核心概念を理解し、実践例で練習することです。

Q:データベースを効果的に練習するには? A:シンプルな例から始め、徐々に複雑さを増やし、常にコードをテストしてください。

Q:よくある間違いは? A:コンパイラのエラーメッセージを注意深く読み、常に変数を初期化してから使用してください。


📖 まとめ

トピック 応用
variant 複数型の値
vector<Row> テーブル実装
map インデックス実装
関数オブジェクト WHERE条件実装

📝 練習問題

  1. 初級(難易度 ⭐): データベースプログラムを拡張し、新規テーブルを作成(列:名前、電話、年齢)、3件のデータを挿入し、全件検索。

  2. 中級(難易度 ⭐⭐): 「ソート」機能を追加—— SELECT * FROM table ORDER BY 年齢 をサポート。ヒント:std::sort + ラムダで年齢順ソート。

  3. 上級(難易度 ⭐⭐⭐): 「結合」機能を実装——2つのテーブルを結合(INNER JOIN)、SELECT t1.名前, t2.年齢 FROM t1 JOIN t2 ON t1.id = t2.id。JOINのロジックを設計・実装。


次のレッスン:コースまとめと次のステップ(#53)

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%