シェルパイプラインを介してCSVデータをSQLiteテーブルに挿入するには?

シェルパイプラインを介してCSVデータをSQLiteテーブルに挿入するには?

私は厳密に純粋なCSV形式で結果をstdoutに出力するプログラムを書いています。 (各行はレコードを表し、同じカンマ区切りのフィールドセットを含み、フィールドには小文字の英語の文字、数字、およびドットのみが含まれ、スペースはなく、引用符もありません。エスケープ/エンコードする必要がある記号はありません。

この出力を完全にフィットするSQLiteテーブルにどのようにリダイレクトできますか?

制約に違反するか(たとえば、すでにテーブルにあるレコードと同じプライマリ/セカンダリキーを持つ)、既存のレコードを置き換えるか自動的に削除するかを制御できればよいでしょう。

もちろん、プログラム自体に直接SQLiteデータベース出力サポートを構築することもできますが、可能であればUNIXアプローチを好みます。

答え1

それでも使用するより簡単な解決策を見つけました。sqlite3 .importただし、これは読み取りまたは一時的に名前付きパイプを読み取りません/dev/stdin。むしろこれと.import関連がある。パイプラインオペレータ呼び出しはcat -標準入力から直接読み取られます。

#!/bin/bash

function csv_to_sqlite() {
  local database_file_name="$1"
  local table_name="$2"
  sqlite3 -csv $database_file_name ".import '|cat -' $table_name"
}

database_file_name=$1
table_name=$2

csv_to_sqlite "$database_file_name" "$table_name"

これは、Windowsコマンドシェルでは機能しません。

答え2

2つの方法:

サンプルtest.csvファイル:

GroupName,Groupcode,GroupOwner,GroupCategoryID 
System Administrators,sysadmin,13456,100
Independence High Teachers,HS Teachers,,101
John Glenn Middle Teachers,MS Teachers,13458,102
Liberty Elementary Teachers,Elem Teachers,13559,103
1st Grade Teachers,1stgrade,,104
2nd Grade Teachers,2nsgrade,13561,105
3rd Grade Teachers,3rdgrade,13562,106
Guidance Department,guidance,,107

1)とcsvkit(CSV変換および操作用のコマンドラインツールセット)

輸入するSQLite3データベース:

csvsql --db sqlite:///test_db --tables test_tbl --insert test.csv

入力csvファイルが指定されていない場合、stdinはcsvデータを受け入れます。

... | csvsql --db sqlite:///test_db --tables test_tbl --insert

データ抽出SQLiteデータベース:

sql2csv --db sqlite:///test_db --query 'select * from test_tbl limit 3'

出力:

GroupName,Groupcode,GroupOwner,GroupCategoryID 
System Administrators,sysadmin,13456,100
Independence High Teachers,HS Teachers,,101
John Glenn Middle Teachers,MS Teachers,13458,102

2)とSQLite3コマンドラインツール(ユーザーはSQL文を手動で入力して実行できます)SQLiteデータベース)

" .import"コマンドを使用して、CSV(カンマ区切り値)データをSQLiteテーブルにインポートします。 " .import"コマンドには、2つのパラメータ、つまりCSVデータを読み取るディスクファイル名と、CSVデータを挿入するSQLiteテーブル名があります。

コマンドを実行する前に、モードをcsvに設定することが重要です.import。これは、コマンドラインシェルが入力ファイルのテキストを別の形式に解釈するのを防ぐために必要です。

$ sqlite3
sqlite> .mode csv
sqlite> .import test.csv test_tbl
sqlite> select GroupName,Groupcode from test_tbl limit 5;
"System Administrators",sysadmin
"Independence High Teachers","HS Teachers"
"John Glenn Middle Teachers","MS Teachers"
"Liberty Elementary Teachers","Elem Teachers"
"1st Grade Teachers",1stgrade
sqlite> 

答え3

Unixシリーズシステムではsqlite3注文する.importCSVの内容は特殊ファイルの標準入力から読み取ることができます/dev/stdin

$ printf "col1,col2\na,1\nb,2\n" | sqlite3 test.db ".import --csv /dev/stdin test"
$ sqlite3 -csv -header test.db "SELECT * FROM test"
col1,col2
a,1
$ sqlite3 -version
3.32.3 2020-06-18 14:00:33 7ebdfa80be8e8e73324b8d66b3460222eb74c7e9dfd655b48d6ca7e1933cc8fd
b,2

答え4

次のbash関数はcsv_to_sqlite標準入力からCSVコンテンツを読み取り、次のコマンドを使用してSQLiteデータベーステーブルにインポートします。sqlite3注文する.import一時的な名前付きパイプ(FIFO):

#!/bin/bash

function csv_to_sqlite() {
  local database_file_name="$1"
  local table_name="$2"
  local temp_input_fifo=$(mktemp -u)
  mkfifo $temp_input_fifo
  sqlite3 -csv $database_file_name ".import $temp_input_fifo $table_name" &
  cat > $temp_input_fifo
  rm $temp_input_fifo
}

database_file_name=$1
table_name=$2

csv_to_sqlite "$database_file_name" "$table_name"
$ printf "col1,col2,col3\na,1,2.6\nb,2,5.4\n" | ./csv_to_sqlite test.sqlite test
$ sqlite3 -csv -header test.sqlite "SELECT * FROM test"
col1,col2,col3
a,1,2.6
b,2,5.4

関連情報