先日参加してきた FOSS4G Hokkaido 2025 にて、DuckDBの話を聞いて、表記のことをやってみたくなりました。
実は2月のイベントで DuckDBの機能を伺ったときにも、やってみたいと考えていたのですが、すっかり先延ばしになっていたので、今回改めて刺激を注入していただいて、手を動かしてみた次第。
目的・環境
DuckDBのインストール
以下のURLにアクセスして、自分の環境をポチポチ。
duckdb.org
ZIPファイルを取得して展開する方法とwingetコマンドを使用する方法があり、今回は、自分に馴染みが薄かったという理由で(体験として)wingetコマンドを使ってみることにしました。
winget install DuckDB.cli
インストールはこれだけ。お手軽。

DuckDB操作の基本
コマンドライン(いわゆるDOSプロンプト)から duckdb を起動する。
C:\Users\myname>duckdb DuckDB v1.4.0 (Andium) b8a06e4a22 Enter ".help" for usage hints. Connected to a transient in-memory database. Use ".open FILENAME" to reopen on a persistent database. D help ツキ
Dというプロンプトが表示され、そこにコマンドを打ち込む。上記は(誤って)helpと入力したところ。
2行目の入力を促すプロンプトが表示される。「次」を要求しているのか、プロンプトが「ツキ」というのが個性的なツールだと感じた。
(たぶんそうではなく、化けている)
duckdbの(データ操作ではない)コマンドは基本的に、先頭に「.」をつける。とりあえず覚えておくのは以下の2つ。
spatial extensionのインストール
GISデータを扱うための拡張をインストールし、使える状態にする。Dはプロンプト。INSTALLは1回だけやれば良い。LOADはduckdbを起動する都度行う必要がある(設定ファイルに書くこともできるが今回はサクサクと先に進む)。
D INSTALL spatial;
D load spatial;
シェープファイルを見る
シェープファイル(.shp)をFROMに指定して、あたかもテーブルであるかのように読むことができる。Windowsの場合のパスの区切りが \ のままで使えるのに好印象( / に書き換えたり \\ にしたりしないといけないものも多いので)。
C:\>duckdb (略) D SELECT * FROM 'D:\work\gis\chibanzu_abiko\ABIKO_AN.SHP'; ┌───────┬───────┬───────┬────────┬─────────┬───┬─────────┬─────────┬──────────────────────┬──────────────────────┐ │ ALIVE │ LAYER │ LTYPE │ SUBLAY │ SUBLTYP │ … │ EL │ STR │ ATR │ geom │ │ int32 │ int32 │ int32 │ int32 │ int32 │ │ varchar │ varchar │ varchar │ geometry │ ├───────┼───────┼───────┼────────┼─────────┼───┼─────────┼─────────┼──────────────────────┼──────────────────────┤ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-16 │ 8-16 │ 65763,8-16,409,004… │ MULTIPOINT (21033.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-20 │ 8-20 │ 65764,8-20,409,004… │ MULTIPOINT (21048.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-24 │ 8-24 │ 65765,8-24,409,004… │ MULTIPOINT (21047.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-6 │ 8-6 │ 65760,8-6,409,0040… │ MULTIPOINT (21016.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-11 │ 8-11 │ 65761,8-11,409,004… │ MULTIPOINT (21036.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-18 │ 8-18 │ 65762,8-18,409,004… │ MULTIPOINT (21032.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 8-8 │ 8-8 │ 65769,8-8,409,0040… │ MULTIPOINT (21072.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 9-10 │ 9-10 │ 65770,9-10,409,004… │ MULTIPOINT (21078.… │ │ 1 │ 21 │ 11 │ 0 │ 0 │ … │ 9-14 │ 9-14 │ 65771,9-14,409,004… │ MULTIPOINT (21094.… │ :(略)
実はこのシェープファイル、日本語部分の文字がShift_JISで格納されており、バケないで取得するにはもう一工夫が必要。
以下のように ST_Read()関数を用いて、第2引数にオプションとしてShift_JIS(CP932)であることを与えれば良い。
SELECT * FROM ST_Read('D:\work\gis\chibanzu_abiko\ABIKO_POL.SHP',open_options=['ENCODING=CP932']);
フォーマット変換してファイルへの出力
COPY テーブル名 TO '出力ファイル名' WITH (FORMAT GDAL, DRIVER 'ファイル形式');
で指定したファイル形式に出力される。主なものとしては以下のようなファイル形式に変換可能(括弧内は DRIVERに指定する文字列。ParquetのみFORMATに指定可能)。
GeoPackage(GPKG)、1JSONのGeoJSON(GeoJSON)、各行1件のGeoJSON(GeoJSONSeq)、FlatGeobuf(FlatGeobuf)、GeoParquet(FORMAT PARQUET)
テーブル名としてSELECT文も書くことができるので、実際の使い方はこんな感じ(GeoPackageに変換)。
COPY (SELECT * FROM 'D:\work\gis\chibanzu_abiko\ABIKO_AN_hiki.SHP') TO 'ABIKO_AN_hiki.gpkg' WITH (FORMAT GDAL, DRIVER 'GPKG');
先ほど解消した文字コード問題に対応した書き方だと、こうなる(こちらはGeoJSONにしてみた)。
COPY (SELECT * FROM ST_Read('D:\work\gis\chibanzu_abiko\ABIKO_OOAZA_POL.SHP',open_options=['ENCODING=CP932'])) TO 'ABIKO_OOAZA_POL.geojson' WITH (FORMAT GDAL, DRIVER 'GeoJSON');"
対話型でなくコマンドとしての実行
ここまでは、duckdbの対話型モードにSELECT文などを書いて実施してきたが、コマンドから実行できれば、まとめてバッチ処理で変換したりの道が拡がる。
これは、duckdbに -c オプションでSQL文を与えれば良い。前述の通り LOAD spatial を起動のたびに実施する必要があるので、これも指定する。以下のように独立した -c として書いておくと、実施したいSQL文をそのまま2番目の -c に書けば良いので、少しだけ手間が減ったり作業ミスが減らせそう。
duckdb -c "load spatial;" -c "COPY (SELECT * FROM ST_Read('D:\work\gis\chibanzu_abiko\ABIKO_AN.SHP',open_options=['ENCODING=CP932'])) TO 'ABIKO_AN2.gpkg' WITH (FORMAT GDAL, DRIVER 'GPKG');"
参考記事
以下の記事を参考にさせていただきました。ありがとうございました!
そういえば、2月のFOSS4G Hokkaido 2024の井口さんの講演でduckdbのspatial extensionの事を知り、会場で早速インストールして動かしたら文字化けしたので訊ねると、湯谷さんのブログに解消法がある旨おしえてもらったのでした。「湯谷さん、今日会場に来てますよ」の言葉と共に(笑)。その節はおふたりともありがとうございました。
追記
この記事を書いたときには、これいいじゃん!!と興奮したのですが、その後、データの詳細を確認して行くにつれ課題も出てきました。どうもこの手順では .projファイルを見ていないようです。 .geojsonに変換したときにも座標系情報が含まれていなかったし、.gpkgへ変換してQGISで確認した際も(そこだけ見れば結構良い感じだったけど)背景地図載せてみたら全然違う場所に表示されていたなど、もう少し工夫が必要、あるいはこの方法では対応できないかも、な感じがします。もうちょっと調査が必要。