MySQL 15 min read

MySQLでCSVを取り込む ― LOAD DATAのERROR 1290・3948と、LOCALで黙って入る不正な行

※この記事にはアフィリエイト広告(プロモーション)が含まれます。

MySQL で CSV を表に取り込むには LOAD DATA を使います。ファイルをサーバーが読む LOAD DATA INFILE と、クライアントが読んで送る LOAD DATA LOCAL INFILE の2つがあり、必要な設定もエラーの扱いも違います。この記事の出力は MySQL 8.4.11(Ubuntu 26.04 の標準パッケージ)で採りました。

まず見る(結論)

LOAD DATA INFILE '/var/lib/mysql-files/item.csv'
  INTO TABLE item
  FIELDS TERMINATED BY ',' ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  IGNORE 1 LINES;
  • LOAD DATA INFILE のファイルは secure_file_priv のディレクトリ(Ubuntu では /var/lib/mysql-files/)に置く
  • LOCAL はサーバーの local_infile=ON とクライアントの --local-infile=1 の両方が要る
  • LOCAL は不正な行があっても止まらず、警告を出して値を変えて入れる。取り込んだら SHOW WARNINGS を見る
  • Windows で作った CSV は LINES TERMINATED BY '\r\n'

エラー別の原因

エラー 原因 対処
ERROR 1290 … --secure-file-priv option ファイルが secure_file_priv の外にある /var/lib/mysql-files/ に置く/LOCAL を使う
ERROR 1045 … Access denied for user 'app1'@'localhost' FILE 権限が無い(ログインはできている) GRANT FILE ON *.* TO .../LOCAL を使う
ERROR 3948 … Loading local data is disabled サーバーの local_infile が OFF SET GLOBAL local_infile = ON
ERROR 2068 … file request rejected due to restrictions on access クライアントで --local-infile を付けていない mysql --local-infile=1
ERROR 1366 … Incorrect integer value: 'id' 見出し行を値として読んだ IGNORE 1 LINES
ERROR 1366 … '21' 先頭に BOM がある BOM を外す/見出し行ごと IGNORE 1 LINES で飛ばす
ERROR 1300 … Invalid utf8mb4 character string Shift_JIS の CSV CHARACTER SET cp932
ERROR 1062 … Duplicate entry '1' 主キーの重複 IGNORE か REPLACE

ERROR 1045 はパスワード違いと同じメッセージですが、-e の中身を実行する段階で出ています。

LOAD DATA INFILE(サーバーが読む)

SHOW VARIABLES LIKE 'secure_file_priv';
+------------------+-----------------------+
| Variable_name    | Value                 |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+

このディレクトリは mysql ユーザーしか入れない(drwx------ mysql mysql)ので、root でコピーして所有者を mysql にしました。/tmp などに置いたまま実行すると、次のエラーになります。

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

取り込んだ CSV と結果は次のとおりです。

id,name,price,created
1,りんご,120,2026-10-01
2,"みかん, 箱",980.5,\N
3,,0,2026-10-03
+----+----------------+--------+------------+
| id | name           | price  | created    |
+----+----------------+--------+------------+
|  1 | りんご         | 120.00 | 2026-10-01 |
|  2 | みかん, 箱     | 980.50 | NULL       |
|  3 |                |   0.00 | 2026-10-03 |
+----+----------------+--------+------------+

NULL にしたいフィールドは \N と書きます。空のフィールド(3行目の name)は NULL ではなく空文字になりました。

LOAD DATA LOCAL INFILE(クライアントが読む)

MySQL 8.4 の既定では local_infile が OFF です。サーバーとクライアントの組み合わせで結果が変わりました。

サーバー local_infile クライアント --local-infile=1 結果
OFF なし ERROR 3948
OFF あり ERROR 3948
ON なし ERROR 2068
ON あり 取り込める
SET GLOBAL local_infile = ON;
$ mysql -u app1 -p --local-infile=1 -e "LOAD DATA LOCAL INFILE '/tmp/fsvmy/item.csv' INTO TABLE fsv.item ..."

SET GLOBAL は再起動で OFF に戻ります。どの PC からでも任意のファイルを送れる設定なので、作業が終わったら OFF に戻しました。

LOCAL では不正な行が警告だけで入る

型の違う値・列の過不足・長すぎる値を混ぜた CSV で比べました。

id,name,price,created
10,a,1,2026-10-01
11,b,x,2026-10-01
12,c,3
13,d,4,2026-10-01,extra
14,e,,2026-10-01
15,ffffffffffffffffffffffffff,5,2026/10/01

LOAD DATA INFILE は2行目で止まり、1行も入りませんでした。

ERROR 1366 (HY000): Incorrect decimal value: 'x' for column 'price' at row 2

LOAD DATA LOCAL INFILE はエラーにならず、6行とも入りました。

SHOW WARNINGS;
| Warning | 1366 | Incorrect decimal value: 'x' for column 'price' at row 2                  |
| Warning | 1261 | Row 3 doesn't contain data for all columns                                |
| Warning | 1262 | Row 4 was truncated; it contained more data than there were input columns |
| Warning | 1366 | Incorrect decimal value: '' for column 'price' at row 5                   |
| Warning | 1265 | Data truncated for column 'name' at row 6                                 |

+----+----------------------+-------+------------+
| id | name                 | price | created    |
+----+----------------------+-------+------------+
| 10 | a                    |  1.00 | 2026-10-01 |
| 11 | b                    |  0.00 | 2026-10-01 |
| 12 | c                    |  3.00 | NULL       |
| 13 | d                    |  4.00 | 2026-10-01 |
| 14 | e                    |  0.00 | 2026-10-01 |
| 15 | ffffffffffffffffffff |  5.00 | 2026-10-01 |
+----+----------------------+-------+------------+

LOCAL は IGNORE を付けたのと同じ扱いになり、LOAD DATA INFILE ... IGNORE INTO TABLE でも同じ警告の一覧になりました。mysql コマンドの -e で実行したときは件数も警告の有無も表示されなかったので、同じ接続の中で SHOW WARNINGS を続けて打ちます。

改行コード・BOM・文字コード

CRLF の CSV を LINES TERMINATED BY '\n' のまま入れると、最後の列の末尾に \r(0D)が残りました。

SELECT id, created, HEX(created), LENGTH(created) FROM item_s;
|  1 | 2026-10-01 | 323032362D31302D30310D |              11 |

文字列の列なので見た目では分からず、WHERE created = '2026-10-01' に当たらなくなります。LINES TERMINATED BY '\r\n' にすると 10 バイトになりました。最後の列が DATE 型の表では、\r があってもエラーにならず、日付として入りました。

Shift_JIS の CSV に対して CHARACTER SET cp932 を付けると、utf8mb4 の列に「あい」として入りました。

LOAD DATA INFILE '/var/lib/mysql-files/sjis.csv' INTO TABLE item CHARACTER SET cp932 FIELDS TERMINATED BY ',';

重複・列の並び替え・変換

LOAD DATA INFILE '...' IGNORE  INTO TABLE item ...;   -- 重複した行は飛ばす
LOAD DATA INFILE '...' REPLACE INTO TABLE item ...;   -- 重複した行は CSV の値で置き換える

LOAD DATA INFILE '/var/lib/mysql-files/item.csv' INTO TABLE item
  FIELDS TERMINATED BY ',' ENCLOSED BY '"' IGNORE 1 LINES
  (id, name, @price, @created)
  SET price = NULLIF(@price, ''), created = STR_TO_DATE(@created, '%Y-%m-%d');

CSV の列を @変数 で受けて SET で変換すると、空欄を NULL にしたり、日付の形式を変えたりできます。列の並びが表と違うときも、ここに CSV の順で列名を書きます。

CSV に出力する

SELECT * FROM item INTO OUTFILE '/var/lib/mysql-files/out.csv'
  FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';

出力先も secure_file_priv の中に限られます(外は ERROR 1290)。同じ名前のファイルがあると ERROR 1086 (HY000): File '/var/lib/mysql-files/out.csv' already exists になり、上書きはされません。NULL は \N で出ました。

関連: MySQLのERROR 1062「Duplicate entry」 / MySQLのERROR 1366「Incorrect string value」 / PostgreSQLでCSVを入出力する(COPY)

MySQL をもっと深く知るための本

MySQL徹底入門 第5版 MySQL 8.4 LTS対応

翔泳社・2025年6月・MySQL 8.4 LTS 対応

MySQL 8.4 に対応した入門書。日本MySQLユーザ会のメンバーが執筆している。

Amazonで見る

MySQL運用・管理[実践]入門 〜安全かつ高速にデータを扱う内部構造・動作原理を学ぶ

技術評論社・2024年5月

内部構造と動作原理から、運用・管理の考え方を学ぶ。

Amazonで見る

Amazonのアソシエイトとして、FIRE SE は適格販売により収入を得ています。