SQLite3でTSVをインポートするときにパスを渡せない問題
外部から呼び出すときにファイル参照できなくなる。
成果物
Python.dataset.SQLite3.Tsv2Insert.201703211257
開発環境
- Linux Mint 17.3 MATE 32bit
- SQLite 3.8.2
- Python 3.4.3
問題の概要
SQLite3でTSVをインポートするときにパスを渡せないせいで外部から呼び出した時に動作しないことがある。
ちょっと説明が面倒でわかりにくい。ようするに.sqlファイル内でパスを動的にできないせいで、相対パスが思うようにならない。tsvファイルを参照するときに参照できなくなってしまう。.importコマンド実行時に困る。
.sql内でシェルスクリプトのように現在ファイルパスやディレクトリパスを取得できたらいいのだが、シェルコマンドが使えない。引数も受け取れない。固定パスしか使えない。
絶対パスにすればいいのだが、バックアップなどで異なるパスになった場合に動作しなくなるため困る。
正常時
SQLite3でtsvをインポートするとき、以下のような構成で、以下のように実行できる。
bash Run.sh
| ファイル名 | 説明 |
|---|---|
| Run.sh | SQLite3ファイルにTSVファイルのデータをインポートする。 |
| TestDB.sqlite3 | 対象DBファイル |
| insert.sql | SQLite3のimportコマンド |
| SomeTable.tsv | SomeTableテーブルに挿入するデータ |
Run.sh
sqlite3 ./TestDB.sqlite3 < ./insert.sql
DB
| 項目 | 名前 |
|---|---|
| DBファイル | TestDB.sqlite3 |
| テーブル | SomeTable |
挿入
insert.sql
.mode tabs .import ./insert.tsv SomeTable
insert.tsv
Column1 Column2 r1c1 r1c2 r2c1 r2c2 r3c1 r3c2
Pythonで呼び出す
python3 Main.py
Main.py
import subprocess import shlex subprocess.call(shlex.split("bash ./Run.sh"))
| ファイル名 | 説明 |
|---|---|
| Run.py | SQLite3ファイルにTSVファイルのデータをインポートする。 |
| Run.sh | SQLite3ファイルにTSVファイルのデータをインポートする。 |
| TestDB.sqlite3 | 対象DBファイル |
| insert.sql | SQLite3のimportコマンド |
| SomeTable.tsv | SomeTableテーブルに挿入するデータ |
問題
insert.sqlファイル内にある./insert.tsvが参照できなくなる場合がある。
insert.sql
.mode tabs .import ./insert.tsv SomeTable
以下のような構成にしておく。
- /test/
- Main.py
- create
- Run.sh
- TestDB.sqlite3
- insert.sql
- SomeTable.tsv
- create
- Main.py
以下のように実行する。
python3 Main.py
カレントディレクトリは/test/である。
このとき、先述のinsert.sql内の./insert.tsvは/test/insert.tsvと解釈される。しかし実際には/test/create/insert.tsvにある。よって参照できない。
使えない解決案
sqlite3コマンドに.tabs .import ./insert.tsv SomeTableコマンドを渡す- SQLite3では
.sqlファイルパスを渡すことしかできない
- SQLite3では
insert.sqlに引数を渡す- SQLite3には
.sqlファイルに引数を渡す機能がない
- SQLite3には
- Run.shで
.importコマンドを実行する.importはSQLite3文脈でないと実行できない.tabs .import ./insert.tsv SomeTableの処理内容を.shファイル内で表現できればパスの問題は解決できただろうに…
insert.sqlファイル内でdirname $0などのコマンドを使う.sqlファイル内ではシェルコマンドが使えない
SQLite3だけでは不可能。事実上、今回のように.sqlから外部ファイル(.tsv)を参照する場合、外部から呼び出せない。
何か方法があるのかもしれないが、知らないし思いつかない。
解決案
pythonでツールを作る。
tsv2insert.py "{TSVファイルパス}" "{SQLite3ファイルパス}" "テーブル名"
SomeTable.tsv
{1行目は列名を書いたヘッダ行}
{2行目以降はデータ行}
datasetを使う。
所感
何か方法があるはずだとは思うのだが知らない。
前々から疑問だったし、使いづらかった。仕方ないからツールを作った。