14
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust で DuckDB を操作する方法 – メモリ上のデータベースで簡単な SQL 実行

Posted at

Rust をやりたい!DuckDB も触りたい!
ということで Rust から DuckDB を操作し、データの作成・挿入・取得をやってみました!

1. DuckDB とは?

DuckDB は、列指向のデータベースであり、組み込みデータベースながら高速なクエリ処理を実現します。
特に、データ分析用途 に適しており、Python や Rust などの言語から簡単に利用できます。

DuckDB の特徴

  • 軽量でシンプルなインターフェース
  • メモリ内データベースを簡単に作成可能
  • SQL による直感的なデータ操作
  • Rust からの操作も簡単!

2. Rust から DuckDB を使う準備

Rust で DuckDB を利用するには、まず duckdb クレートを Cargo に追加します。

Cargo.toml
[dependencies]
duckdb = { version = "1.1.1", features = ["bundled"]}

duckdb クレートは現在時点での最新バージョン v1.1.1 を使用します。

features = ["bundled"] オプションは、DuckDB クレート内にバンドルされた
DuckDB ライブラリを使用するように設定するオプションです。
これにより、依存ライブラリのインストールが不要となるため
システムに DuckDB がインストールされていなくてもクレートをそのまま利用できる
ようになります。

3. Rust で DuckDB を操作する

ここでは、Rust を使ってメモリ上にデータベースを作成し
データを挿入・取得する
サンプルコードを紹介します。

main.rs
use duckdb::{Connection, Result};

fn main() -> Result<()> {
    // メモリ上に DuckDB データベースを作成
    let conn = Connection::open_in_memory()?;

    // データベースを作成してデータを挿入
    conn.execute("CREATE TABLE users (id INTEGER, name VARCHAR);", [])?;
    conn.execute(
        "INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');",
        [],
    )?;

    // データを取得
    let mut stmt = conn.prepare("SELECT * FROM users;")?;
    let rows = stmt.query_map([], |row| {
        let id: i32 = row.get(0)?;
        let name: String = row.get(1)?;
        Ok((id, name))
    })?;

    // 結果を表示
    for row in rows {
        let (id, name) = row?;
        println!("id: {}, name: {}", id, name);
    }
    Ok(())
}

4. コードの解説

① メモリ上のデータベースを作成

let conn = Connection::open_in_memory()?;

DuckDB は、ファイルを作成しなくてもメモリ上にデータベースを作成できます。
Connection::open_in_memory() を使うことで、手軽に一時的なデータベースを扱えます。

② テーブルの作成とデータの挿入

conn.execute("CREATE TABLE users (id INTEGER, name VARCHAR);", [])?;
conn.execute(
    "INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');",
    [],
)?;

execute() を使用して、SQL の CREATE TABLE や INSERT を実行できます。

③ データの取得

let mut stmt = conn.prepare("SELECT * FROM users;")?;
let rows = stmt.query_map([], |row| {
    let id: i32 = row.get(0)?;
    let name: String = row.get(1)?;
    Ok((id, name))
})?;

prepare() を使ってSQL文を準備して
query_map() を用いて、取得したデータをタプル (id, name) にマッピング

④ 結果の表示

for row in rows {
    let (id, name) = row?;
    println!("id: {}, name: {}", id, name);
}

取得したデータをループで回して、コンソールに出力します。

5. 実行結果

上記のコードを実行すると、次のような結果が表示されます。

id: 1, name: Alice
id: 2, name: Bob
id: 3, name: Charlie

どうでしょう?
結構簡単に操作できてしまいましたね!
簡単だったので、少しコードを修正してみたいと思います。

6. Prepared Statementを活用した改善版

上記のコードでは execute() を直接使ってレコードを挿入していましたが
Prepared Statement を利用すると
SQL文を事前に準備し、複数回の実行を効率化 できます。

以下の修正を加えました:

  • 名前のリストを配列で定義
  • Prepared Statement を事前に用意し、ループで再利用
  • ToSql トレイトを活用し、動的に値をバインド

修正後のコード

main.rs
use duckdb::{Connection, Result, ToSql};

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;
    conn.execute("CREATE TABLE users (id INTEGER, name VARCHAR);", [])?;

		// 名前のリストを配列で定義
    let names = ["Liam", "Noel", "Paul", "Tony"];
    
    // Prepared Statement を事前に用意
    let mut stmt = conn.prepare("INSERT INTO users VALUES (?, ?);")?;
    
    // Prepared Statement をループ処理で再利用
    for (i, name) in names.iter().enumerate() {
        let id = (i as i32) + 1;
        // execute() の引数 params にパラメータのスライスを渡す
        // duckdb::ToSql にキャストし型推論を行わせる
        stmt.execute([&id as &dyn ToSql, &name as &dyn ToSql])?;
    }

    let mut stmt = conn.prepare("SELECT * FROM users;")?;
    let rows = stmt.query_map([], |row| {
        let id: i32 = row.get(0)?;
        let name: String = row.get(1)?;
        Ok((id, name))
    })?;

    for row in rows {
        let (id, name) = row?;
        println!("id: {}, name: {}", id, name);
    }
    Ok(())
}

7. 実行結果(改善版)

id: 1, name: Liam
id: 2, name: Noel
id: 3, name: Paul
id: 4, name: Tony

8. まとめ

本記事では、Rust から DuckDB を使いメモリ上でデータベースを作成・操作する方法を
紹介しました。

DuckDB はシンプルで使いやすく、データ分析用途にも最適です。

次に試したいこと

  • ファイルベースの DuckDB (Connection::open("mydb.db"))
  • より複雑なクエリ を試す(集計・結合など)
  • WASM 版 DuckDB を活用して、ブラウザ上で SQL を実行

Rust を使ってデータ処理に DuckDB を活用してみましょう! 🚀

14
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?