外部から呼び出すときにファイル参照できなくなる。
成果物
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を使う。
所感
何か方法があるはずだとは思うのだが知らない。
前々から疑問だったし、使いづらかった。仕方ないからツールを作った。