- ベストアンサー
PHP+MySQLでのcsvファイルインポートの方法と注意点:桁区切りのカンマに対応する方法
- PHP + MySQLで外部システムからのcsvファイルをテーブルにインポートする方法について解説します。
- csvファイルの特徴として、各フィールドがダブルクォートで囲まれ、カンマで区切られており、金額の項目には桁区切りのカンマが入っています。
- 桁区切りのカンマの処理について解決策を提案します。事前にcsvを加工せずに取り込む方法をご紹介します。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
> "0001","あああああ",…(中略)…,"105,000","100,000","5,000" 常にこの書式であるという前提ですが、ファイルを1行ずつ読んで カラム区切りをタブに変え、項目の整形を行う方法があります。 一度お試しください。 $file_name = "test.csv"; //LOADファイル //ファイルオープン $fp = fopen("./$file_name", "r"); $fw = fopen("./$file_name.tmp", "w"); //変換先ファイル while(!feof($fp)){ $buf = fgets($fp, 2048); $buf = str_replace("\",\"","\t",$buf); // 「","」を「\t」に置換 $buf = str_replace("\"","",$buf); // 「"」を「」に置換 //mb_convert_variables("UTF-8", "SJIS", $buf); // SJISをUTF-8に変換する場合 fputs($fw, $buf); } //ファイルクローズ fclose($fp); fclose($fw); //タブ区切りでLOAD(パラメータは環境に合わせて調整ください) $sql = "LOAD DATA LOCAL INFILE './$file_name.tmp' REPLACE INTO TABLE data_table FIELDS TERMINATED BY '\t'; $res = mysql_query($sql); // mysql_connect、mysql_closeは省略 if(!$res){ echo "LOAD ERROR!!"; } $ret = unlink("./$file_name.tmp"); //変換先ファイルの削除 CSVはSJISだと思いますが、PHPの文字コードと異なる場合、 日本語を含んでいると文字化けを起こす場合があります。 念のため、PHPの文字コードに合わせ、mb_convert_variablesで"UTF-8"か"EUC"に しておくほうがよいかと思います。
その他の回答 (3)
- yambejp
- ベストアンサー率51% (3827/7415)
#1です >FIELDS TERMINATED BY ',' のカラム区切りのカンマと誤認されているのが問題だと思っています。 たぶんちがうと思いますよ 単にカンマ付きのデータなので読めるところまでよんで 後は捨てられているだけだと思います。 誤認されていたらカラムが右にずれていくのでわかると思います。 そもそもエンクローズの指定をしてるのだからターミネーターが 誤認されたらCSVとして成り立たないでしょう >カラムがずれた状態で受けてしまうのではないかと思うのですが、間違ってますでしょうか? 前述したとおり間違ってます。 せめて試してから再質問してほしかったです。
お礼
再度の回答ありがとうございます。 そして申し訳ありません。おっしゃるとおり、試してから再質問すべきでした。 私がENCLOSED やTERMINATEDの意味をちゃんと理解できていないようです。 #1にお礼を投稿した後ではありますが、#1のアドバイスを単純には試して見ましたが、エラーが帰ってきて誤ったデータ更新すらできずにおります。 実際のデータはフィールド数も多く、SQL文も相当長くなってしまって、記述の仕方がまずかったのか、うまく試すことすらできていない状態でして…。 ENCLOSED BY…の後の( )内はテーブルにある全項目を列挙する必要があって、@の変数へ入れるものだけ項目名の変わりに"@変数名"として、SET以降はREPLACEした項目だけでよろしいのでしょうか。 質問時の文で誤った実行結果を出してみると、ご指摘の通り、カラムがずれているというよりは、金額項目のカンマ以降の数字が捨てられているようでした。例の場合、税込みに105が入り、次の税抜きに100が入っているようです。 ちなみに、思いついて質問文にESCAPED BY ',' をつけてみたところ、カンマ以下が0の場合(たとえば、525,000)にだけ525とおかしな結果になるようで、525,123の場合ならば、正しく格納されるようです。 この場合、#1で意図されるような記述を正しく私が書ければ上手く行くのでしょうか。 もう少し試行錯誤してみたいと思います。
- taka451213
- ベストアンサー率47% (436/922)
こんばんは。 普通に入らんですかね・・・? ENCLOSED BY '\"' この円マークは何ですか?
補足
PHPからMySQLを操作しようとしています。 \は ’(シングルクォート)をエスケープするために入れました。 エスケープしないとPHP側でエラーを起こすような気がしますが…。 今のままだと、カラムの区切りのカンマと、105,000の5と0の間のカンマが区別されず、インポートはできても正しいデータがテーブルに入りません。 テストのために、csvファイルをExcelなどで開き、105,000→105000としてインポートするとうまくいきました。 ただ、毎回Excelなどでデータを修正して使うのではなく、直接インポートさせるようにしたいと思っています。
- yambejp
- ベストアンサー率51% (3827/7415)
一回変数に受けてせっとするとか? //test.txt "0001","あああああ","105,000","100,000","5,000" //hogeテーブル コード,項目名,税込み,税抜き,消費税 LOAD DATA INFILE 'test.txt' INTO TABLE hoge FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' (コード,項目名,@TEMP1,@TEMP2,@TEMP3) SET 税込み=REPLACE(@TEMP1,',',''),税抜き=REPLACE(@TEMP2,',',''),消費税=REPLACE(@TEMP3,',','');
お礼
回答ありがとうございます。 恥ずかしながら、変数に一度受ける方法を初めて知りました。 しかしながら、今回の場合、"105,000円"に使われているカンマが、FIELDS TERMINATED BY ',' のカラム区切りのカンマと誤認されているのが問題だと思っています。 (読み込むと、105だけが該当のフィールドに読み込まれているようです。) この方法だと、変数に受けようにも、カラムがずれた状態で受けてしまうのではないかと思うのですが、間違ってますでしょうか? 実際はフィールド数もかなりあって、検証するだけでも大変でして…。 さらなるアドバイスがあれば、お知恵をお貸し下さい。 やはり、csv自体を先に読み込んで加工するような処理をした方がよいのでしょうか。
お礼
回答ありがとうございます。 どうやらcsv自体を直してしまうほうが早いようですね。 お教え頂いた方法ならば、思っていたよりファイル加工の手間もかからないようですので、今回はこちらの方法でいこうと思います。 試しに上のとおりに実行させて頂いたところ、金額の部分が105,000→105しか格納されませんでしたが、上のソースにさらにカンマを除去するために $buf = str_replace(",","",$buf); を加えることでうまくいきました。 '105,000' という値のままでは、DECIMAL型のフィールドに取り込まれなかったのかな、と理解してます。 何はともあれ、無事に処理ができるようになりました。 勉強になりました。ありがとうございます。