LoginSignup
1
1

More than 5 years have passed since last update.

MySQL へ大量のCSVファイルをbashでインポートする

Last updated at Posted at 2018-08-08
1 / 5

大量のCSVファイルをインポートするためにシェル組んだので残しておく

MySQL8.0 で実行

$ mysql --version
mysql  Ver 8.0.11 for Linux on x86_64 (MySQL Community Server - GPL)

設定ファイルに以下を記述する必要があった
記述しないと 「 The used command is not allowed with this MySQL version 」って怒られる

/etc/my.cnf
[client]
loose-local-infile=1

もしかしたら以下も実行しとく必要があったかも


mysql> SET PERSIST local_infile= 1;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              1 |
+----------------+
1 row in set (0.00 sec)

mysql>

MySQL 8.0でLOAD DATA LOCAL INFILEが "ERROR 1148 (42000): The used command is not allowed with this MySQL version" で失敗する時
(参考にさせていただきました)


大量のCSVをインポートするシェル

実行ディレクトリにある ~.csv ファイルを全部読み込んでインポートします

#!/bin/bash

## INIT
PWD="PasSw0rd"
TOTAL=`ls *.csv | wc -l`

## テーブルクリア
echo 'TRUNCATE TABLE csv_table;' | MYSQL_PWD=$PWD mysql -u UserName DBName -s -N

## ディレクトリ内の CSV ファイルを対象にループ
ls `pwd`/*.csv | while read line
do
  ## CSV の行数取得
  L=`cat "$line" | wc -l`

  ## カウンタ
  cnt=`echo $(($cnt + 1))`

  ## 処理ファイル表示
  echo "$line" | awk -v"cnt=$cnt" -v"total=$TOTAL" -v"line=$L" '{ printf("%3d/%3d %\0477d %s\n", cnt, total, line, $0);}'

  ## インポート処理
  MYSQL_PWD=$PWD mysql -u UserName DBName << EOT
  LOAD DATA LOCAL INFILE '$line'
  INTO TABLE csv_table
  FIELDS
    TERMINATED BY ','
    ENCLOSED BY '"'
  LINES
    TERMINATED BY '\r\n'
  IGNORE 1 LINES;
EOT
done

## 結果行数表示
echo 'select count(*) from csv_table;' |
MYSQL_PWD=$PWD mysql -u UserName DBName -s -N |
awk '{printf("\nIMPORT %\047d  Record\n", $0);}'

CSVファイルの先頭1行を読み飛ばしてます( IGNORE 1 LINES )
CSVはカンマ区切り( TERMINATED BY ',' )
CSVはダブルクォーテーションで囲まれてる( ENCLOSED BY '"' )
CSVの行の終わりは改行 ( TERMINATED BY '\r\n' )
CSV ファイルはUTF8 で作ってありました

実行時には以下のような表示を行います

  1/128      56 /path/file1.csv
・・・・・
128/128   9,440 /path/file128.csv

IMPORT 201,289  Record

インポートしたデータのカラム毎のデータバリエーション数とレコード数確認

CSVにデータがあったのか、カラム毎にとりあえず確認してみる


#!/bin/bash

## INIT
PWD="PasSw0rd"

echo "desc csv_table;" |
MYSQL_PWD=$PWD mysql -u UserName DBName -s -N |
awk '{print $1;}' |
while read line
do

  col=$(echo $line | sed -e 's/\//_/g')
  echo "$line" | awk '{printf("SELECT `%s`, count(*) FROM csv_table GROUP BY `%s` ORDER BY 2 DESC, 1\n", $1, $1);}' |
  MYSQL_PWD=$PWD mysql -u UserName DBName -s -N >  "lst.$col"

  cnt=`cat "lst.$col" | wc -l`

  if [ $cnt -ne 1 ]
  then
    echo "$line" | awk -v"cnt=$cnt" '{printf("%\0477d %s\n", cnt, $0);}'
    if [ $cnt -lt 10 ]
    then
      cat "lst.$col" | awk '{printf("          : %s\n", $0);}'
    fi
  fi

done

カラム内のデータバリエーションがない場合は表示対象外にして( if [ \$cnt -ne 1 ] )
バリエーションが少ない場合はデータ内容毎のレコード数を表示してみる( if [ \$cnt -lt 10 ] )

実行結果はこんな感じ

109,790 xxキー
 40,927 xx番号
 46,699 xx名
 21,118 xxxx
     14 xxxxxx
    223 xxx
      2 xx種別
          :     201051
          : 001 238
  4,862 xxxxxxxxx
 ・・・・・

 xxキー は 109,790のバリエーションがあり
 xx種別 は 2 バリエーションあり、内容は 空白が 201,051レコード、種別 001 が 238レコード
のような表示になります

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1