プログラミング言語を整える
中級DuckDB を整える。
= サーバー不要の分析用データベース DuckDB を、手元の CSV を SQL で集計しながら学ぶ
DuckDB が初めての方は、先に そもそも DuckDB とは・どんな場面で使うか をどうぞ。
DuckDBとは
アプリやノートブックの中に組み込んで使う分析用のデータベースで、サーバーを立てずに CSV や Parquet のファイルを SQL で集計できます。
| 誕生 | 2019年 |
|---|---|
| 作った人・組織 | オランダの研究機関 CWI(Centrum Wiskunde & Informatica)の Mark Raasveldt と Hannes Mühleisen。現在は DuckDB Labs が開発し、DuckDB Foundation がプロジェクトを管理しています |
| 種類 | 組み込み型の分析用(列指向)データベース |
| ライセンス | MIT License |
| 得意なこと | 大量の行をまとめて集計する分析の処理を、サーバーを用意せずに手元の1台で速く行えます。 |
| 手元で動かすには | duckdb(CLI を起動)/Python からは pip install duckdb |
日本での使われ方
- Python(pandas など)や R でのデータ分析で、表の集計を SQL で書きたいときに使われています。
- サーバーを立てずに、手元の CSV や Parquet のファイルをそのまま SQL で読んで集計する用途で使われています。
- Jupyter などのノートブックの中で、分析の途中の集計に使われることがあります。
- データ基盤の前処理や、ログの集計を手元で試すときの道具としても使われています。
使えるクラウドサービス
- MotherDuck(DuckDB のクラウドサービス。手元の DuckDB とクラウド上のデータを組み合わせて使えます)
研修・学習での位置づけ
DuckDB はサーバーを立てずに動くため、SQL の練習や、データ分析の研修で手軽に使えます。DuckDB 専用の資格は、知られている範囲ではありません。SQL の書き方そのものは PostgreSQL に近いため、ほかのデータベースの学習にもつなげられます。
関わる資格
このデータベース専用の資格は、確認できた範囲ではありません。
ブラウザでDuckDBを動かす
本物の DuckDB(DuckDB-WASM)をこのページの中で動かします。手元の CSV を選ぶと、そのまま SQL で集計できます。ファイルも SQL も端末の外には出ません。最初の1回だけ、処理系(約8MB・展開すると約34MB)をこのサイトから読み込みます。
-- 準備のデータ(products と orders)が入った状態で流れます FROM products SELECT category, count(*) AS items GROUP BY ALL ORDER BY items DESC;
CREATE TABLE products ( id INTEGER PRIMARY KEY, name VARCHAR NOT NULL, category VARCHAR NOT NULL, price INTEGER NOT NULL ); INSERT INTO products VALUES (1, 'りんご', '果物', 150), (2, 'みかん', '果物', 80), (3, '牛乳', '飲み物', 200), (4, 'お茶', '飲み物', 120), (5, '食パン', 'パン', 250); CREATE TABLE orders ( id INTEGER PRIMARY KEY, product_id INTEGER NOT NULL, qty INTEGER NOT NULL, ordered_on DATE NOT NULL ); INSERT INTO orders VALUES (1, 1, 3, '2026-10-01'), (2, 3, 1, '2026-10-01'), (3, 2, 5, '2026-10-02'), (4, 1, 2, '2026-10-03'), (5, 4, 4, '2026-10-03');
選んだファイルは、この端末の中で DuckDB に渡すだけで、どこにも送られません。選ぶと、read_csv で読む SQL がエディタに入ります。
結果
「実行」を押すと、準備のデータ(下の「準備(全お題共通)」)を入れてから、エディタのコードを流します。
この練習場でできること・できないこと
- 動いているのは本物の DuckDB v1.4.3 を WebAssembly にした DuckDB-WASM です。結果もエラーのメッセージも本物と同じです。
- 手元の CSV は「手元の CSV を読む」で選びます。選んだファイルはこの端末の中で DuckDB に渡すだけで、送信はしません。
- インターネット上のファイル(https:// の URL)や拡張機能の読み込みはしません(外への通信をしない方針のため)。
- データベースはこのページを開いている間だけ続きます。5秒を超える問い合わせは止めます(データベースは空に戻ります)。
そもそも DuckDB とは
手元のファイルを、そのまま SQL で集計できる、分析向けのデータベース。
DuckDB(ダックディービー)は、組み込み型の分析向け(列指向)リレーショナルデータベースです。サーバーを立てる必要がなく、アプリやスクリプトの中から呼び出して動かします。CSV などのファイルを取り込まずに、そのまま SQL で集計できるのが特徴です。
「分析向けの SQLite」とよく紹介されます。SQLite は少量のデータを一件ずつ読み書きする用途、DuckDB は大量の行をまとめて集計する用途が得意です。PostgreSQL や MySQL のように、多くの人が同時に使うサーバーとして動かす道具とは役割が違います。
どこで・どんな場面で使うか
-
手元の CSV を集計する
売上やアクセスのログを、専用のサーバーなしで SQL で集計できます。
-
Python や R からの分析
データ分析のプログラムの中から呼び出して、大きなデータをすばやく処理できます。
-
データの下ごしらえ
分析やレポートの前に、ファイルを結合・整形する作業を SQL で書けます。
-
ブラウザの中でも動く
WebAssembly 版があり、このサイトの練習場のように、ブラウザだけで集計を試せます。
-
求人での位置づけ
比較的新しい道具なので、必須条件として書かれることはまだ多くありません。データ分析・データエンジニアの仕事では、土台になる SQL の経験が問われます。
向いている場面・向いていない場面
- 向いている場面:大量の行の集計、ファイルを直接読む分析、一人でデータを調べる作業。
- 向いていない場面:多くの人が同時にデータを書き換える業務システム。こちらは PostgreSQL や MySQL の得意分野です。
- SQL が土台。覚えた SQL がそのまま活きるので、分析の道具を増やしたいときの次の一歩になります。
上の練習場では、本物の DuckDB がブラウザの中で動きます。手元の CSV を読み込んで、集計を試してみてください。
6つのお題をDuckDBで書く
PostgreSQL・MySQL・DuckDB・MongoDB・Redis の5ページで、同じ商品と注文のデータに同じ6つのお題を並べています。SQL の方言の違いや、SQL を使わないデータベースでの考え方の違いがそのまま比べられます。
表示している結果とエラーのメッセージは、DuckDB v1.4.3(DuckDB-WASM 1.32.0) で実際に流して、一字一句同じになることを確かめたものです。上の練習場で動いているのも同じ処理系です。結果の表は、見比べやすいように全ページで psql に寄せた同じ形にそろえています(NULL は NULL と表示)。
準備(全お題共通)表を作ってデータを入れるコード。お題2〜6・クイズ・エラーの例は、これを流した後に続けて流した結果です。
CREATE TABLE products ( id INTEGER PRIMARY KEY, name VARCHAR NOT NULL, category VARCHAR NOT NULL, price INTEGER NOT NULL ); INSERT INTO products VALUES (1, 'りんご', '果物', 150), (2, 'みかん', '果物', 80), (3, '牛乳', '飲み物', 200), (4, 'お茶', '飲み物', 120), (5, '食パン', 'パン', 250); CREATE TABLE orders ( id INTEGER PRIMARY KEY, product_id INTEGER NOT NULL, qty INTEGER NOT NULL, ordered_on DATE NOT NULL ); INSERT INTO orders VALUES (1, 1, 3, '2026-10-01'), (2, 3, 1, '2026-10-01'), (3, 2, 5, '2026-10-02'), (4, 1, 2, '2026-10-03'), (5, 4, 4, '2026-10-03');
SQL(DuckDB)
CREATE TABLE products ( id INTEGER PRIMARY KEY, name VARCHAR NOT NULL, category VARCHAR NOT NULL, price INTEGER NOT NULL ); INSERT INTO products VALUES (1, 'りんご', '果物', 150), (2, 'みかん', '果物', 80), (3, '牛乳', '飲み物', 200), (4, 'お茶', '飲み物', 120), (5, '食パン', 'パン', 250); CREATE TABLE orders ( id INTEGER PRIMARY KEY, product_id INTEGER NOT NULL, qty INTEGER NOT NULL, ordered_on DATE NOT NULL ); INSERT INTO orders VALUES (1, 1, 3, '2026-10-01'), (2, 3, 1, '2026-10-01'), (3, 2, 5, '2026-10-02'), (4, 1, 2, '2026-10-03'), (5, 4, 4, '2026-10-03'); SELECT * FROM products ORDER BY id;
結果
id | name | category | price ----+--------+----------+------- 1 | りんご | 果物 | 150 2 | みかん | 果物 | 80 3 | 牛乳 | 飲み物 | 200 4 | お茶 | 飲み物 | 120 5 | 食パン | パン | 250 (5 行)
DuckDB の型は INTEGER・VARCHAR・DATE のように書きます。文字列の長さを決めずに VARCHAR とだけ書けるので、表を作るのが手軽です。DuckDB では SELECT * を省いて「FROM products;」とだけ書いても、同じように表の中身を見られます。CSV ファイルから表を作るときは、CREATE TABLE products AS SELECT * FROM read_csv('products.csv'); のように read_csv で直接読み込めます(Parquet は read_parquet)。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
SQL(DuckDB)
SELECT name, category, price
FROM products
WHERE price >= 100 AND category IN ('果物', '飲み物')
ORDER BY price DESC; 結果
name | category | price --------+----------+------- 牛乳 | 飲み物 | 200 りんご | 果物 | 150 お茶 | 飲み物 | 120 (3 行)
WHERE・IN・ORDER BY の書き方は、ほかの SQL のデータベースと同じです。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
SQL(DuckDB)
SELECT category, count(*) AS cnt, round(avg(price), 1) AS avg_price FROM products GROUP BY ALL ORDER BY category;
結果
category | cnt | avg_price ----------+-----+----------- パン | 1 | 250.0 果物 | 2 | 115.0 飲み物 | 2 | 160.0 (3 行)
GROUP BY ALL は DuckDB の書き方で、SELECT に並べた列のうち集計関数の外にあるもの(ここでは category)を GROUP BY の対象にします。GROUP BY に同じ列名を書き直す手間が省けます。avg の結果は DOUBLE(小数)になるので、round で小数点以下1桁にそろえています。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
SQL(DuckDB)
SELECT o.id AS order_id, p.name, o.qty, p.price * o.qty AS amount FROM orders o JOIN products p ON p.id = o.product_id ORDER BY o.id;
結果
order_id | name | qty | amount ----------+--------+-----+-------- 1 | りんご | 3 | 450 2 | 牛乳 | 1 | 200 3 | みかん | 5 | 400 4 | りんご | 2 | 300 5 | お茶 | 4 | 480 (5 行)
JOIN … ON の書き方はほかの SQL のデータベースと同じです。o.id と p.id はどちらも id という名前なので、AS order_id と別名を付けて区別しています。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
SQL(DuckDB)
SELECT name, price FROM products ORDER BY price DESC LIMIT 2 OFFSET 2;
結果
name | price --------+------- りんご | 150 お茶 | 120 (2 行)
LIMIT で1ページの件数を、OFFSET で読み飛ばす件数を指定します。2ページ目なので、先頭の2件を飛ばしています。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
SQL(DuckDB)
INSERT INTO products VALUES (2, 'みかん', '果物', 90), (6, 'バナナ', '果物', 100) ON CONFLICT (id) DO UPDATE SET price = excluded.price; SELECT * FROM products ORDER BY id;
結果
id | name | category | price ----+--------+----------+------- 1 | りんご | 果物 | 150 2 | みかん | 果物 | 90 3 | 牛乳 | 飲み物 | 200 4 | お茶 | 飲み物 | 120 5 | 食パン | パン | 250 6 | バナナ | 果物 | 100 (6 行)
ON CONFLICT (id) DO UPDATE は、主キー(PRIMARY KEY)の id がぶつかったときに更新へ切り替える書き方で、excluded は「入れようとした行」を指します。DuckDB では INSERT OR REPLACE INTO products VALUES (…) と短く書くこともでき、その場合は行全体が入れ替わります。
同じお題をほかのデータベースで: PostgreSQL・MySQL・MongoDB・Redis
出力当てクイズ
準備のデータを入れた後に流したときの、最後の SQL の結果を選んでください。選ぶと正解と理由が出ます(答えはどこにも送られず、記録もしません)。
問1
SELECT 7 / 2;
画面に出るのは?
DuckDB の / は、整数どうしでも小数(DOUBLE)で答えを返します。7 / 2 は 3.5 です。PostgreSQL や SQL Server では整数どうしの / は切り捨てになるので、違いに気を付けます。
問2
SELECT 7 // 2;
画面に出るのは?
// は DuckDB の整数の割り算で、小数点以下を切り捨てた 3 を返します。/ と // を使い分けます。
問3
SELECT [10, 20, 30][1];
画面に出るのは?
DuckDB にはリスト(LIST)型があり、[10, 20, 30] のように書けます。添字は 1 から数えるので、[1] は先頭の 10 です。
問4
SELECT 'abc' || NULL;
画面に出るのは?
|| で文字列をつなぐとき、片方が NULL だと結果も NULL になります。NULL を空の文字列として扱いたいときは concat('abc', NULL) を使うと abc になります。
よくあるエラーと直し方
書き始めの人が出会いやすいエラーです。メッセージは英語のまま出るので、どの言葉を手がかりにすればよいかもあわせて載せています。
SELECT のつづり間違い
エラーになるコード
SELEC * FROM products;
画面に出るメッセージ(抜粋)
Parser Error: syntax error at or near "SELEC"
何が起きているか:SELECT のつづりが違うため、SQL の文として読めません。at or near のあとに、読めなかった場所が出ます。
直し方:つづりを SELECT に直します。
無い表を指定した
エラーになるコード
SELECT * FROM product;
画面に出るメッセージ(抜粋)
Catalog Error: Table with name product does not exist!
何が起きているか:表の名前 products の s が抜けていて、その名前の表がありません。
直し方:表の名前を確かめて products に直します。SHOW TABLES; で今ある表の一覧を見られます。
GROUP BY に無い列を選んだ
エラーになるコード
SELECT category, name, count(*) AS cnt FROM products GROUP BY category;
画面に出るメッセージ(抜粋)
Binder Error: column "name" must appear in the GROUP BY clause or must be part of an aggregate function.
何が起きているか:category ごとにまとめた結果に、まとめていない name を出そうとしています。1つのグループに name が複数あるため、どれを出すか決まりません。
直し方:name を GROUP BY に加えるか、SELECT から外します。DuckDB では GROUP BY ALL と書くと、集計関数の外にある列がすべてグループの対象になります。
主キーが重複した
エラーになるコード
INSERT INTO products VALUES (1, 'ぶどう', '果物', 400);
画面に出るメッセージ(抜粋)
Constraint Error: Duplicate key "id: 1" violates primary key constraint.
何が起きているか:id は主キー(PRIMARY KEY)なので、すでにある id 1 の行をもう1つ入れられません。
直し方:新しい id(例: 6)を使うか、更新したいときは ON CONFLICT (id) DO UPDATE や INSERT OR REPLACE を使います。
ほかのデータベースの解説
- PostgreSQL 1986年にカリフォルニア大学バークレー校で始まった研究プロジェクト POSTGRES が元で・リレーショナルデータベース
- MySQL 1995年・リレーショナルデータベース
- MongoDB 2009年・ドキュメント指向データベース
- Redis 2009年・インメモリのキーバリューストア
5つのデータベースと SQLite を並べた比較は データベースを整える にあります。 書いたコードはどこにも送られません(このページに入力欄はクイズの選択だけで、選んだ答えも記録しません)。
このツールについて
アプリやノートブックの中に組み込んで使う分析用のデータベースで、サーバーを立てずに CSV や Parquet のファイルを SQL で集計できます。
DuckDB の概要と、同じ6つのお題・出力当てクイズ・よくあるエラー。ブラウザの中で本物の DuckDB が動き、手元の CSV をそのまま SQL で集計できます。
主な機能
- 概要(誕生・作った人・種類・ライセンス)と日本での使われ方・クラウドサービス・研修と資格
- 同じ商品と注文のデータで6つのお題(PostgreSQL・MySQL・MongoDB・Redis の同じお題へ移れる)
- 出力当てクイズ4問(正解と理由)
- よくあるエラー4件(実際のメッセージ・原因・直し方)
- 本物の DuckDB v1.4.3(DuckDB-WASM)が動く練習場
- 手元の CSV を選んで read_csv で集計(ファイルは端末の中だけ)・送信ゼロ
よくある質問
Q. 手元の CSV はどこかに送られますか?
A. 送られません。選んだファイルはこの端末の中で読み込み、ページの中で動いている DuckDB に渡すだけです。処理系もこのサイト自身から読み込み、外部の配信元は使っていません。
Q. DuckDB は PostgreSQL や MySQL と何が違いますか?
A. サーバーを立てずにアプリやノートブックの中に組み込んで使う、集計や分析に向いたデータベースです。データを列ごとにまとめて持つので、たくさんの行を集計する問い合わせが得意です。一方で、多くの利用者が同時に書き込む Web サービスの裏側には、PostgreSQL や MySQL のようなサーバー型が向いています。
Q. 練習場の DuckDB は本物ですか?
A. 本物です。DuckDB v1.4.3 を WebAssembly にした DuckDB-WASM 1.32.0 を動かしていて、結果もエラーのメッセージも本物と同じです。インターネット上のファイルの読み込みや拡張機能のインストールは、外への通信をしない方針のため行いません。
入力値はURLの「#」以降に入るためサーバーには送信されません。リンクを開くと同じ状態を復元します。
続けて整える
データの時点:各ページに記載の版(各プロジェクトの公式リリース)