
こんにちは。よっしーです(^^)
今日は、AWKでCSVファイルからLOAD DATA文を作成する方法についてご紹介します。
背景
AWKでCSVヘッダーを参照して、load data 文を作成する機会があったので、そのときの内容を備忘としてのこしました。
作成ファイル一覧
下記のファイルを作成しました。
gen_load_data_sql.sh
gen_head_value.awk
gen_set_value.awk
gen_load_data_sql.sh
#!/bin/bash
csvPath=test.csv
head=$(head -n 1 ${csvPath} | awk -f gen_head_value.awk)
setValue=$(head -n 1 ${csvPath} | awk -f gen_set_value.awk)
cat << EOS > load_test.sql
LOAD DATA
LOCAL
INFILE '${csvPath}'
INTO TABLE sample
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(${head})
SET ${setValue}
;
EOS
gen_head_value.awk
BEGIN {
FS=",";
OFS=",";
}
{
for(i=1; i<=NF; i++) {
printf("@%d%s", \
i, \
(i!=NF) ? OFS : "" );
}
}
gen_set_value.awk
BEGIN {
FS=",";
OFS=",";
}
{
for(i=1; i<=NF; i++) {
value=($i=="uuid") ? "UUID_TO_BIN(@" i ")" : "@" i;
printf("`%s`=%s%s%s", \
$i, \
value, \
(i!=NF) ? OFS : "",
ORS);
}
}
実行結果
下記のtest.csvを用意します。
id,uuid,value,created_at,updated_at
1,2D04153F-02B9-4E4B-9327-03B3B196CBD6,840,2023-11-26 15:35:40,2023-11-27 15:35:40
2,717058B8-2866-42C6-ACB5-D5BB359A26D2,394,2023-11-26 15:35:40,2023-11-28 15:35:40
3,0BC6EB72-41A5-4C2D-9937-E93F5BC5DCE9,783,2023-11-26 15:35:40,2023-11-29 15:35:40
下記のファイルが出力されていれば成功です。
下記のコマンドを実行します。
bash gen_load_data_sql.sh
下記のファイルが出力されていれば成功です。
load_test.sql
ファイル内容は下記になります。
LOAD DATA
LOCAL
INFILE 'test.csv'
INTO TABLE sample
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(@1,@2,@3,@4,@5)
SET `id`=@1,
`uuid`=UUID_TO_BIN(@2),
`value`=@3,
`created_at`=@4,
`updated_at`=@5
;
解説
gen_head_value.awk
このawkスクリプトは、CSV形式のファイルを処理して、各行のフィールド(列)に対して特定の形式で番号をつけて出力するものです。以下にコードの各部分の解説を示します。
BEGIN {
FS=",";
OFS=",";
}
BEGINブロック: プログラムが実行される前に初期化を行うためのブロックです。FS=",":FS(Field Separator) をカンマに設定します。これはCSV形式のファイルで各列がカンマで区切られていることを意味します。OFS=",":OFS(Output Field Separator) をカンマに設定します。これにより、printfでデフォルトの出力フィールドセパレータを使用する際に、出力される各フィールドの間にカンマが挿入されます。
{
for(i=1; i<=NF; i++) {
printf("@%d%s", \
i, \
(i!=NF) ? OFS : "" );
}
print ""; # 改行を追加して次の行に移行
}
- 通常のブロック: 各行に対する処理を行います。
for(i=1; i<=NF; i++): 各フィールドに対して繰り返し処理を行います。printf("@%d%s", i, (i!=NF) ? OFS : "" ): 各フィールドに対して、「@番号」の形式で出力します。三項演算子(i!=NF) ? OFS : ""は、最後のフィールド以外の場合にはカンマOFSを追加し、最後のフィールドの場合には何も追加しないようにしています。print "";: 各行の処理が終わったら、改行を追加して次の行に移行します。
例えば、入力が “A,B,C” のようなCSV行であれば、このスクリプトは “@1,@2,@3” という形式で出力します。
gen_set_value.awk
このawkスクリプトは、CSV形式のファイルを処理して、各行のフィールド(列)に対して特定の条件で処理を行いながら出力するものです。以下にコードの各部分の解説を示します。
BEGIN {
FS=",";
OFS=",";
}
BEGINブロック: プログラムが実行される前に初期化を行うためのブロックです。FS=",":FS(Field Separator) をカンマに設定します。これはCSV形式のファイルで各列がカンマで区切られていることを意味します。OFS=",":OFS(Output Field Separator) をカンマに設定します。これにより、printfでデフォルトの出力フィールドセパレータを使用する際に、出力される各フィールドの間にカンマが挿入されます。
{
for(i=1; i<=NF; i++) {
value=($i=="uuid") ? "UUID_TO_BIN(@" i ")" : "@" i;
printf("`%s`=%s%s%s", \
$i, \
value, \
(i!=NF) ? OFS : "",
ORS);
}
}
- 通常のブロック: 各行に対する処理を行います。
for(i=1; i<=NF; i++): 各フィールドに対して繰り返し処理を行います。value=($i=="uuid") ? "UUID_TO_BIN(@" i ")" : "@" i;: 各フィールドの値に対して条件分岐を行い、uuidの場合はUUID_TO_BIN(@i)に変換し、それ以外の場合は元の値@iを保持します。printf("%s=%s%s%s", $i, value, (i!=NF) ? OFS : "", ORS);: 各フィールドに対して、「フィールド名=変換後の値」の形式で出力します。フィールドの間にはOFSで指定されたカンマが挿入され、行末にはORSで指定された改行が追加されます。
例えば、入力が “id,uuid,value” のようなCSV行であれば、このスクリプトは “id=1, uuid=UUID_TO_BIN(@2), value=@3″ といった形式で出力します。
gen_load_data_sql.sh
このBashスクリプトは、与えられたCSVファイル (test.csv) からMySQLのLOAD DATAコマンドを生成し、その結果をload_test.sqlファイルに書き込みます。以下に各部分の解説を示します。
csvPath=test.csv: CSVファイルのパスを変数csvPathに設定しています。head=$(head -n 1 ${csvPath} | awk -f gen_head_value.awk): CSVファイルの先頭行(ヘッダー)を取得し、awkスクリプトgen_head_value.awkを適用して、MySQLのLOAD DATAコマンドで使用するヘッダーの部分を生成し、変数headに格納しています。setValue=$(head -n 1 ${csvPath} | awk -f gen_set_value.awk): CSVファイルの先頭行を取得し、awkスクリプトgen_set_value.awkを適用して、MySQLのSET句の部分を生成し、変数setValueに格納しています。cat << EOS > load_test.sql: ヒアドキュメントを使用して、load_test.sqlファイルを生成するための開始を示します。LOAD DATA...: MySQLのLOAD DATAコマンドを指定しています。ここで、${head}と${setValue}にはそれぞれヘッダーとSET句の内容が挿入されます。EOS: ヒアドキュメントの終了を示しています。
簡単にまとめると、このスクリプトは与えられたCSVファイルからMySQLのLOAD DATAコマンドを生成し、それをload_test.sqlファイルに書き込んでいます。生成されたload_test.sqlファイルは、MySQLに対してデータの一括挿入を行う際に使用できます。
おわりに
今日は、AWKでCSVファイルからLOAD DATA文を作成する方法についてご紹介しました。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)


コメント