2026-10-01
· Dylan YuCSVからSQLiteへ:CSVデータをデータベースにインポートする4つの方法
CSVをSQLiteに取り込む実践的な4つの方法——sqlite3 CLI、DB Browser、DBeaver、pandas——に加えて、インポートを静かに台無しにするエンコーディング、区切り文字、型アフィニティの罠を解説します。
CSVがあります。それをSQLiteに入れたい。これは2分の仕事のはずで、たいていはそうなります——そうでなくなるまでは。
私は数え切れないほど何度もCSVをSQLiteにインポートしてきました。Google Sheetsからエクスポートされたスプレッドシート、クライアントの古いMySQLマシンからのデータベースダンプ、誰かが.csvにリネームしたログファイル、そしてBOMとセミコロン区切り付きのUTF-16だったことが判明した忘れがたいファイルなど、さまざまです。それらはどれも「ただのCSV」でした。
これを行うためのまともな方法が4つあり、どれを選ぶかは2つの質問に依存します。これをどれくらいの頻度で行うのか、そしてCSVはどれくらい乱れているのか。一度きりでファイルがきれいなら、sqlite3 CLIが3行でやってくれます。毎週スクリプトからインポートを再実行するなら、Pythonが欲しいでしょう。ファイルがぐちゃぐちゃで、デバッグするよりクリックしたいなら、GUIウィザードがその価値を発揮します。
短くまとめると:
sqlite3CLI — きれいな一度きりのファイルに最速。macOSではインストール不要。明示しない限りすべてがTEXTです。- DB Browser for SQLite — 区切り文字、エンコーディング、ヘッダーのオプションを備えたGUIウィザード。良い中間策です。
- DBeaver — ファイルが本当に厄介なとき、あるいはすでにDBeaverを常用しているときのインポートウィザード。単純なファイルには過剰です。
- Python + pandas — インポートが反復可能、スクリプト化可能、あるいはパイプラインの一部である必要があるときの答え。
実際のコマンドを使って4つすべてを見ていき、その後、ほとんどのチュートリアルが飛ばす部分——実際に何がうまくいかないのか、そしてデータが着地した後にどう修正するのか——を扱います。
インポートの前に:CSVで実際に何がうまくいかないか
CSVは仕様——RFC 4180——を持つ形式ですが、ほとんど誰も従っていません。それがほとんどの痛みの根源です。私が最もよく遭遇するものを挙げます。
エンコーディングとUTF-8 BOM
最もよくある単一の失敗:WindowsのExcelからエクスポートされたCSVは、しばしばUTF-8 with BOM(バイト順マーク)として保存されるか、時折Windows-1252 / Latin-1として保存されます。BOMはファイルの先頭にある3つの目に見えないバイトです。インポートツールがそれらを取り除かないと、最初のカラムヘッダーがidではなく\ufeffidになり、idを参照するすべてのクエリが「no such column」で失敗します。
最初のカラム名の先頭にやのような奇妙な文字が見えたら、それがBOMです。sqlite3 CLIでは、通常ファイルを事前にクリーニングすることで問題を避けられます。Pythonでは、encoding="utf-8-sig"を渡せばpandas.read_csvが処理します。
非UTF-8エンコーディングはこのもう半分です。Windows-1252で保存されたファイルはインポートできますが、アクセント付き文字が文字化けします(caféではなくcafé)。修正するには、行を手作業で編集するのではなく、正しいエンコーディングでデコードします。
カンマ以外の区切り文字
名前にもかかわらず、多くの「CSV」ファイルはセミコロン区切り(ヨーロッパのExcelエクスポートで一般的で、カンマが小数点記号です)、タブ区切り、またはパイプ区切りです。sqlite3 CLIは.separatorでこれらを扱えますが、区切り文字がセミコロンであることに気づかないと、1つの巨大なカラムになります。
カンマ、引用符、改行を含むクォートされたフィールド
ここで素朴なパーサーが壊れます。正しく形成されたCSVは、カンマ、引用符、または改行を含むフィールドをクォートします:
id,name,notes
1,"Smith, John","He said ""hello"" and left"
2,Jane,"Line one
Line two"
sqlite3のCSVインポータとpandasはどちらもこれを正しく扱います。自分のスクリプトのsplit(",")は扱えません。行数がおかしくなる——行が多すぎる——なら、それはほとんど常に、クォートされたフィールド内の埋め込み改行を素朴なパーサーが2つのレコードに分割したためです。
一貫性のない日付フォーマット
1つのカラム、3つのフォーマット:2026-01-15、01/15/2026、15 Jan 2026。SQLiteにはネイティブの日付型がないので、着地したものはテキストとして着地し、ORDER BY dateは辞書順でソートしてナンセンスな結果を返します。1つのフォーマット(私はISO 8601、YYYY-MM-DDを使います)を決め、インポートの前または後に正規化してください。
先頭のゼロ
郵便番号、電話番号、製品SKU——先頭にゼロがあるものすべて。インポートでカラムをINTEGERとして宣言すると、00501は501になります。TEXTとして着地させれば、ゼロは残ります。これは意図的に下さなければならない型の判断です。
空のカラムと空行
末尾のカンマは空の末尾カラムを生みます。空行はすべての値が空の行を生みます。どちらもエラーになりません——ただ静かにテーブルを汚染します。インポートの前にファイルをざっと見る価値があります。
「すべてがTEXT」という結果
これが最大のもので、SQLite特有です。SQLiteは動的型付けです。PostgreSQLやMySQLのようにカラム型を強制しません。代わりに、各カラムは型アフィニティ——値がどう保存されるべきかのヒント——を持ち、各値のストレージクラスは値ごとに決まります。
実際にはこういうことです。sqlite3 CLIがCSVをインポートするとき、あなたが先に自分でテーブルを作っていない限り、テーブルのカラムを宣言された型なしで作成します。宣言された型のないカラムはBLOBアフィニティを持ち、値はテキストとして入ります。つまり、19.99の値でいっぱいのpriceカラムはTEXTであり、5でいっぱいのquantityカラムもTEXTであり、値が文字列として保存されるためSUM(quantity)は期待どおりに動かないかもしれません。
数値に見えるテキストに対してSUM()を実行することはできます——SQLiteが変換します——が、保証は失われ、比較は微妙に奇妙になり、スキーマを読むあらゆるツールは型をまったく見られません。修正策は、欲しい型で自分でテーブルを作成し、それからそこにインポートすることです。以下で示します。
これが全体像です。では4つの方法です。
方法1:sqlite3 CLI
これはきれいな一度きりのファイルに最速の道であり、私のデフォルトです。まずインストールに関する注意:sqlite3はmacOSに同梱されているので、すでに持っています。Windowsではデフォルトでインストールされていません——sqlite.org/download.htmlからコマンドラインツールをダウンロードし、sqlite3.exeをPATHに置きます。これらのドットコマンドの完全なリファレンスはsqlite.org/cli.htmlにあります。
2行のバージョン
最低限は次のようになります:
sqlite3 mydb.db
.mode csv
.import people.csv people
これだけです。.mode csvはCLIに入出力をCSVとして扱うよう指示し、.import file tableはファイルをpeopleという名前のテーブルに読み込みます。
2つの落とし穴があり、どちらも重要です:
- テーブルはすでに存在していなければなりません。
.importはそれを作成しません。peopleが存在しないと、エラーになります。(厄介な点があります。テーブル名が存在せずファイルをインポートしている場合、一部のバージョンはそれを作成します——しかし作成されたテーブルは型のないカラムを持ち、これが「すべてがTEXT」問題です。それに頼らないでください。テーブルを明示的に作成してください。) - カラムの順序が重要で、ヘッダー行はデータとしてインポートされます。
.importはすべての行をデータとして読み込みます。CSVにヘッダーがあるなら、スキップしない限りそのヘッダーが最初の行になります。
ヘッダー行の扱い
現代のsqlite3 CLIは.importで--skipオプションをサポートします:
.mode csv
.import --skip 1 people.csv people
--skip 1は最初の行をスキップします——ヘッダーにまさに欲しいものです。(--skipのない古いビルドなら、古典的な回避策はヘッダーを行としてインポートしてからDELETE FROM people WHERE rowid = 1;を実行するか、ファイルをtail -n +2に通すことです。私は利用可能なら--skipを好みます。)
完全な実例
これをきちんとやりましょう。カラムが本当の型を持つよう明示的なスキーマを使います。people.csvが次のようだとします:
id,name,email,signup_date,account_balance
1,Alice,alice@example.com,2026-01-15,120.50
2,Bob,bob@example.com,2026-02-03,0
3,"Smith, Carol",carol@example.com,2026-02-20,42.00
クォートされた"Smith, Carol"に注意してください——そのカンマはクォートの内側にあり、1つのフィールドのままでなければなりません。セッション全体は次のとおりです:
sqlite3 people.db
-- 1. Create the table with real types BEFORE importing.
CREATE TABLE people (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
signup_date TEXT, -- ISO 8601 date, stored as text
account_balance REAL
);
-- 2. Switch to CSV mode and import, skipping the header row.
.mode csv
.import --skip 1 people.csv people
-- 3. Verify.
SELECT COUNT(*) FROM people; -- expect 3
SELECT * FROM people LIMIT 5;
型を宣言したので、idはINTEGER、account_balanceはREAL、signup_dateはISO日付を保持するTEXTです。クォートされた名前は単一の値Smith, Carolとしてインポートされました。CLIにテーブルを作らせていたら、すべてのカラムが型なしになっていたでしょう。
ファイルが別の区切り文字を使うなら、インポートの前に設定します:
.mode csv
.separator ";"
.import --skip 1 people.csv people
型アフィニティに関する注意
宣言された型があっても、SQLiteのアフィニティ規則は変換であり、ゲートではないことを忘れないでください。INTEGERとして宣言されたカラムは、'abc'を挿入すればそれをテキストとして保存します——SQLiteはそれを拒否しません。型を宣言すると、正しく形成されたデータに対して正しい保存が得られ、SUM()、AVG()、比較、インデックスで正しい振る舞いが得られます。検証が得られるわけではありません。厳密な検証が必要なら、CHECK制約かアプリケーションレベルのチェックが必要です。
方法2:DB Browser for SQLite
DB Browser for SQLiteは無料のオープンソースGUIで、そのCSVインポートウィザードは一度きりのファイルに対してこの中で最も親しみやすいです。ファイルが小さく、コミットする前にプレビューを目で確認したいとき、あるいは助けを求めてきた人がターミナルに慣れていないときに、私はこれを使います。
ワークフロー:
.dbファイルを開くか作成します。- **File → Import → Table from CSV file…**に進みます。
- CSVを選びます。すぐにドロップダウン付きのプレビューが表示されます:
- フィールド区切り文字 — カンマ、セミコロン、タブ、パイプ、またはカスタム文字列。
- 引用符文字 — 通常は
"ですが、一部のエクスポートは'を使います。 - エンコーディング — UTF-8、UTF-16、Latin-1など。ここでBOMと文字化けの問題を修正します。
- 最初の行にカラム名が含まれる — ヘッダーをデータ行ではなくカラム名として使うにはこれをチェックします。
- プレビューグリッドでカラム名と型を編集します。これが決定的な機能です。ここで
idをINTEGER、balanceをREAL、日付をTEXTに設定できるので、「すべてがTEXT」という結果になりません。 - テーブルに名前を付け、OKをクリックすると、1ステップでテーブルを作成し行をインポートします。
CLIに対する利点は、何が起きようとしているかを見られることです——区切り文字、エンコーディング、パースされたカラムはすべて、何かが書き込まれる前に見えます。カンマを含むクォートされたフィールドが壊れるなら、プレビューでカラム数がおかしくなるのがわかります。
トレードオフはクリックが多いことです。毎週同じインポートをウィザードで行うのは退屈で、スクリプトに入れられません。そのためには方法4が欲しくなります。
方法3:DBeaver
DBeaverは汎用データベースクライアントです——SQLite、PostgreSQL、MySQL、その他多数と話します。すでに他のデータベースに使っているなら、そのCSVインポートウィザードのおかげで新しくインストールしたり学んだりする必要がありません。専用設計のSQLiteツールとどう比較されるかの完全な内訳は、私のDBeaver比較にあります。
SQLiteのインポートフロー:
- SQLiteデータベースに接続します(DBeaverは
.dbファイルパスから接続を作成します)。 - 対象のテーブル(新しいテーブルを作るならデータベース)を右クリック → Import Data。
- ソースとしてCSVを選び、ファイルを指定します。
- ウィザードがライブプレビュー付きで、区切り文字、引用符文字、エンコーディング、ヘッダー行を案内します。
- CSVのカラムをテーブルのカラムにマッピングし、既存の行の扱い方(追加、切り捨てなど)を選び、実行します。
DBeaverのウィザードは3つのGUI選択肢の中で最も設定可能です。奇妙なエンコーディング、カスタム区切り文字、カラムマッピングをうまく扱い、本物のSQLクライアントなので、ツールを切り替えずに結果に対してすぐにSELECTクエリを実行できます。
過剰なとき: SQLiteにしか触れず、しかもたまにしか触れないなら、DBeaverは大きく、決して使わない表面積の多いJavaベースのアプリケーションです。単一のきれいなCSVには、sqlite3 CLIを開いて2つのコマンドを打つ方がウィザードより速いです。そして本当に欲しいのがインポートツールではなく結果のテーブルのビューア/エディタなら、より軽量なローカルファーストツールの方が適しています——これがおおよそBaseVoltの機能セットが狙っているギャップです。詳細は最後に。
方法4:Python + pandas
インポートが複数回行われる必要があるなら——毎週のリフレッシュ、ビルドステップ、ETLジョブの一部——スクリプト化するのが正解です。pandasを使ったPythonが標準的なアプローチであり、厄介なケース(エンコーディング、区切り文字、日付、dtype)をCLIよりはるかに優雅に扱います。
核心は2つの呼び出しです。読み込むread_csv、書き込むto_sql。
import sqlite3
import pandas as pd
# 1. Read the CSV. utf-8-sig strips a UTF-8 BOM if present.
df = pd.read_csv(
"people.csv",
encoding="utf-8-sig",
sep=",", # change to ";" for semicolon files
dtype={"id": "Int64"}, # keep id as integer, allow NULLs
parse_dates=["signup_date"],
)
# 2. Normalize text columns (strip stray whitespace).
df["name"] = df["name"].str.strip()
# 3. Write to SQLite. if_exists="replace" rebuilds the table each run;
# use "append" to add rows instead.
with sqlite3.connect("people.db") as conn:
df.to_sql("people", conn, if_exists="replace", index=False)
このパターンについて知っておく価値のあるいくつかのこと:
- **
if_exists="replace"**は実行のたびにテーブルを削除して再作成します——完全なリフレッシュには完璧ですが、テーブルに他のデータがあったり外部キーで参照されていたりすると危険です。行を追加するときは"append"を使います。接続で外部キーを強制する必要があるなら、接続直後にPRAGMA foreign_keys = ON;を設定します。なぜデフォルトでオフなのかは私の外部キーガイドをご覧ください。 - dtypeは重要です。 pandasは型を推論し、欠損値があると
idカラムを喜んでfloatにし、1を1.0にします。dtypeを明示的に宣言すればそれを避けられます。 to_sqlはDataFrameのdtypeから導出されたテーブルの宣言型を使うので、すべてTEXTという結果ではなく、本当のINTEGER / REAL / TEXTカラムが得られます。- 大きなファイルには、メモリ内に1つの巨大なトランザクションを構築する代わりにバッチで書き込むよう、
to_sqlにchunksize=10000を追加します。 - ファイルがメモリに収まらないなら、
read_csvのchunksizeでCSVをチャンク単位で読むこともできます。
これがスケールする方法です。バージョン管理し、CIに入れ、オンデマンドで再実行します。ウィザードとCLIの方法は人間用で、これは機械用です。
比較
| 方法 | 最適な用途 | 乱れたCSVを扱えるか | 反復可能か | セットアップの手間 |
|---|---|---|---|---|
sqlite3 CLI | きれいな一度きりのファイル、素早いインポート | 限定的(区切り文字とヘッダーのみ) | シェルスクリプト経由 | macOSでは不要、Windowsではダウンロード |
| DB Browser for SQLite | 視覚的なプレビューが欲しい一度きりのファイル | 良好(エンコーディング、区切り文字、引用符、型) | いいえ — 手動クリック | GUIをインストール(小さなダウンロード) |
| DBeaver | 乱れたファイル、またはすでにDBeaverを使っているとき | 強力(完全なマッピング、エンコーディング、区切り文字) | いいえ — 手動ウィザード | 大きなJavaアプリをインストール |
| Python + pandas | 反復可能なパイプラインとスケジュールされたインポート | 最強(明示的なエンコーディング、dtype、日付) | はい — 完全にスクリプト化可能 | Python + pandasをインストール |
パターンはこうです。きれいなファイルではCLIが速度で勝ち、乱れた一度きりのファイルではGUIが可視性で勝ち、pandasが反復可能性で勝ちます。単一の最良の答えはなく、だからこそ1つではなく4つの方法なのです。
端から端までの実例
小さくやや乱れたCSVでまとめて、全体の流れ——生のファイルから検証済みのテーブルまで——を見られるようにしましょう。orders.csvとします:
order_id,customer,email,order_date,total,notes
1001,Alice,alice@example.com,2026-03-01,49.99,
1002,"Doe, John",john@example.com,2026-03-02,12.50,"Rush order, ship fast"
1003,Alice,alice@example.com,2026-03-05,0,
3つの実世界のしわに注意してください。カンマを含むクォートされた名前("Doe, John")、カンマを含むクォートされたメモ、2行の空の末尾フィールドです。素朴なsplit(",")は両方のクォートされたフィールドを台無しにするでしょう。
ステップ1 — 型付きでテーブルを作成する。
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer TEXT NOT NULL,
email TEXT,
order_date TEXT, -- ISO 8601
total REAL,
notes TEXT -- empty string -> NULL we'll fix later
);
ステップ2 — インポートする。
.mode csv
.import --skip 1 orders.csv orders
ステップ3 — スキーマを検証する。 .schemaはSQLiteが見るままのCREATE TABLE文を出力し、型が生き残ったことを確認できます:
.schema orders
-- CREATE TABLE orders (
-- order_id INTEGER PRIMARY KEY,
-- customer TEXT NOT NULL,
-- email TEXT,
-- order_date TEXT,
-- total REAL,
-- notes TEXT
-- );
ステップ4 — 行数を検証する。 3行のファイル(プラススキップしたヘッダー)をインポートしたので、3を期待します:
SELECT COUNT(*) FROM orders;
-- 3
--skip 1を忘れていたら、これは4と言い、order_id = 'order_id'の行ができていたでしょう。この単一のチェックが最もよくあるインポートの間違いを捕まえます。
ステップ5 — 厄介な行を抜き取り確認する。 クォートされたフィールドが無傷で通ったことを確認します:
SELECT order_id, customer, total, notes FROM orders;
-- 1001 | Alice | 49.99 | (null)
-- 1002 | Doe, John | 12.50 | Rush order, ship fast
-- 1003 | Alice | 0.0 | (null)
Doe, JohnとRush order, ship fastはそれぞれ単一の値です——クォートが機能しました。そして空の末尾フィールドはNULLとして入りました。これがクリーンアップにつながります。
インポート後にデータを修正する
インポートは簡単な半分です。私がほぼいつも次にやることを紹介します。
型:実際に何が得られたか確認する
型を宣言しなかった(あるいはテーブルを自動で作成するツールを使った)なら、それらを検査します:
SELECT typeof(order_id), typeof(total) FROM orders LIMIT 1;
typeof(total)が'text'を返すなら、数値は文字列です。再構築する代わりに、しばしば型付きでテーブルを再作成してコピーするだけで済みます——あるいはpandasを使っているなら、明示的なdtypeでインポートを再実行します。
日付
SQLiteには日付型がありません。日付はTEXT(ISO 8601がまともな選択です)、INTEGER(Unixエポック)、またはREAL(ユリウス日)として存在します。フォーマットが何であれ、一貫させてください。カラムが混在したフォーマットを持つなら、正規化します:
-- Rewrite US-style MM/DD/YYYY into ISO YYYY-MM-DD.
UPDATE orders
SET order_date = substr(order_date, 7, 4) || '-' ||
substr(order_date, 1, 2) || '-' ||
substr(order_date, 4, 2)
WHERE order_date LIKE '__/__/____';
するとISO文字列は辞書順でソートされるため、ORDER BY order_dateが正しくソートします。もっと複雑なものは、データベースに到達する前にpandasでparse_datesを使って正規化してください——SQLでの文字列操作よりエラーが起こりにくいです。
NULLと空文字列
これは人々を絶えず噛みます。空のフィールドを持つCSVは、NULLではなく空文字列''としてインポートされます。これらは別物です。WHERE notes IS NULLはそれらを見つけられず、COUNT(notes)はそれらを存在するものとして数えます。
-- Turn empty strings into real NULLs.
UPDATE orders SET notes = NULL WHERE notes = '';
下流のクエリとデータツールが正しく振る舞うよう、インポート直後にこれを行ってください。(pandasでは、to_sqlの前にdf.replace("", pd.NA)が同じことをします。)
重複排除
インポートを再実行することは、重複行を得る古典的な方法です。自然キーがあるなら、それを使います:
-- Remove duplicate order_id rows, keeping the lowest rowid.
DELETE FROM orders
WHERE rowid NOT IN (
SELECT MIN(rowid) FROM orders GROUP BY order_id
);
より良いのは、自然キーにUNIQUE制約を付けてスキーマレベルで重複を防ぎ、その後のインポートでINSERT OR IGNOREを使うことです。
主キーの追加
テーブルが主キーなしで作成するツールから来て、自然キーのカラムがあるなら、既存のSQLiteテーブルに制約を追加するのと同じ状況です。ALTER TABLEは主キーを追加できません。テーブルを再構築します——キー付きで新しいテーブルを作成し、行をコピーし、古いものを削除し、リネームします。(余ったカラムがあり、rowidベースの代理キーが欲しいだけなら、すべてのSQLiteテーブルにはすでに暗黙のrowidがあり、何も宣言せずにクエリで使えることに注意してください。)
完全な再構築パターン——そしてなぜ多段階のプロセスなのか——は、私のSQLite外部キーガイドのALTER TABLEセクションをご覧ください。テーブルがきれいになったら、これ以上SQLを書かずに閲覧・編集したいなら、.dbファイルを適切なビューアで開くのが次のステップです。.dbファイルの開き方に関する私のガイドが選択肢を網羅しています。
トラブルシューティング
私が何度も何度も目にする失敗と、その意味:
- "no such table: X" —
.importはテーブルが存在することを要求します。先に作成してください。これはCLIのエラー第1位です。 - 最初のカラム名が
idまたはid— UTF-8 BOM。BOMなしのUTF-8として再保存するか、pandasでencoding="utf-8-sig"でインポートします。 - 行数が期待より1多い — ヘッダーをスキップしていません。
--skip 1(CLI)を追加するか、「最初の行にカラム名が含まれる」(GUI)をチェックします。 - すべてが1つのカラムに着地した — 間違った区切り文字。インポートの前に
.separator ";"(または正しいもの)を設定するか、ウィザードで選びます。 - 行数が高すぎる — クォートされたフィールド内の埋め込み改行が素朴なパーサーに分割されています。CLI、GUIウィザード、またはpandasを使ってください——すべてクォートされた改行を扱えます。
split(",")は扱えません。 - アクセント付き文字が
caféに見える — 間違ったエンコーディング。UTF-8、またはファイルが実際に保存されたエンコーディング(多くの場合Windows-1252)でインポートします。 - 先頭のゼロが消えた(
00501→501)— カラムがINTEGERとして扱われました。TEXTとして宣言します。 SUM()が0かナンセンスを返す — 値がTEXTとして保存され、何かが変換されていません。数値型を宣言して再インポートします。WHERE x IS NULLが何も見つけない — 空のフィールドが''になりました。空文字列からNULLへの更新を実行します。- 数値が
1ではなく1.0と表示される — pandasが欠損値のためにfloatを推論しました。dtype={"id": "Int64"}を設定します。 Error: FOREIGN KEY constraint failed— FK制約のあるテーブルにインポートしていて外部キーが有効な場合、参照される親行が欠けています。親を先に挿入するか、依存順にインポートします。
どれをいつ使うか
私が実際に判断する順の短い判断ガイド:
- 1ファイル、きれい、一度だけ →
sqlite3CLI。3つのコマンドで完了。 - 1ファイル、乱れていて、コミットする前に見たい → DB Browser for SQLite。プレビューがその価値を発揮します。
- すでにDBeaverを常用している、またはファイルが本格的なカラムマッピングを要する → DBeaverのインポートウィザード。
- 来週またこれをやる → Python + pandas。スクリプト化し、バージョン管理し、忘れましょう。
- 結果のテーブルを人間が閲覧・編集できる必要がある → 上記のいずれかでインポートし、適切なツールで
.dbを開きます。
最後のものはほとんどのチュートリアルが途中でやめてしまう部分であり、通常は本当のゴールです。データベースにCSVが欲しいからCSVをインポートすることはめったにありません——データをクエリ、フィルタ、結合、編集したいからそうするのです。sqlite3 CLIはデータを入れますが、住むには貧しい場所です。そこがBaseVoltのようなローカルファーストのデスクトップアプリの出番です。インポートが生成した.dbファイルを指定すれば、数秒で完全なダッシュボード——グリッド、ギャラリー、カンバン、ダッシュボードのビュー、さらにリレーションの可視化——が得られ、スキーマ変更はありません。はっきり言うと、BaseVoltはCSVインポータではありません。CSVは上の4つの方法のいずれかで持ち込み、BaseVoltはその後にテーブルを扱う方法です。macOS(Apple Silicon)とWindows向けのローカルアプリで、PostgreSQL、MySQL、SQLite、Cloudflare D1に接続し、データがlocalhostから出ることはありません——ダウンロードページから入手するか、demo.basevolt.appのライブデモを試せます。特にSQLite側については、/sqliteにもっとあります。
まとめ
CSVをSQLiteにインポートすることは解決済みの問題です——それを行う良い方法が4つあり、正しいものはあなたの状況に依存し、どのツールが「最高」かには依存しません。
sqlite3CLIはきれいな一度きりのものに最速ですが、型付きのテーブルを自動で作成せず、指示しない限りヘッダーをスキップしません。先にテーブルを作成し、それから.mode csvと.import --skip 1です。- DB BrowserとDBeaverはプレビューと本物のエンコーディング/区切り文字/型の制御を提供し、ファイルが乱れているときに重要です。
- pandasは、インポートが複数回行われる必要があるまさにその瞬間に欲しくなるものです。
- 何を使うにせよ、SQLiteの型アフィニティを忘れないでください。型を宣言しなければ、すべてがTEXTです。そして空のCSVフィールドはNULLではなく空文字列になります——それはすぐに修正してください。
インポート自体は5分です。型を宣言し、日付を正規化し、空文字列をNULLに変換するのに費やす10分が、クエリできるテーブルとあなたを驚かせ続けるテーブルの違いを生みます。
データが入ったら、BaseVoltがそれを実際に使う方法です——SQLiteデータベースのためのローカルファーストの管理パネルで、アカウント不要、データはマシンから出ません。
これが役に立ったなら、私はデータベース、ローカルファーストソフトウェア、開発ツールを作る地味な部分について書いています。Xで見つけてください。