お世話になっております。初心者のような質問で恐縮ですが、表題のように、CSVからの登録で数値の先頭に0が付いてしまう現象が起きております。
CSVに文字列、数値など色々なパターンの項目があり、それを一括して(PHPで)DB内に登録するスクリプトを用意したのですが、ある数値のカラムを確認すると、1 が 01、2 が 02 と、先頭に0 が付いた状態で登録されてしまう現象が起きています。(文字列のカラムも数値のカラムも、varcharとして設定)
かといって、数値はどれも0が付くのか?と言えば、問題ないカラムもあれば、数値は全て0が付いてしまうカラムもあるような状況です。
最初は気付かずにいたのですが、selectする際、where文にて数値を条件に振り分けようとしたら5が05となっており振り分けることが出来ずに発覚した次第です。
以上、初めての現象で、調べても同じような不具合の記事等が見つからず質問として投稿させて頂きましたが、何が原因として考えられるのでしょうか?
お忙しいなか恐縮ですがアドバイス頂ければ幸いです。
宜しくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
もしかしてCSVをExcelで見ていませんか?
CSV上で実際は'01'、'02'が設定されているけどExcelで表示しているために0が省略されているように見えているとか。
投稿2015/04/09 00:09
総合スコア3541
0
ベストアンサー
CSVを読み込んでトリムしてからSQL成形をするスクリプトです。
lang
1<?php 2 function formatting_to_sql($v) { 3 //空白文字を除去 4 $v = trim($v); 5 6 if( preg_match('/[^\d]/',$v) ){ 7 //数字以外の文字を含む場合はテキストとして判別して文字コードを変えて返す 8 return mb_convert_encoding($v, "UTF-8", "SJIS"); 9 } 10 if( preg_match('/^0+$/',$v) ){ 11 //テキストが全部0だったら0にして返す 12 return 0; 13 } else { 14 //テキストが数字で0以外の数字があったら先頭の0を省いて返す 15 return intval(preg_replace('/^0*([1-9][0-9]*)$/','$1',$v,1)); 16 } 17 } 18 19 //CSVを読み込む 20 $fp = fopen('sample.csv','r'); 21 22 //一行ずつCSVからデータを取り出しつつループ 23 $i = 0; 24 while( $line = fgetcsv($fp) ){ 25 //ヘッダ行からセル名を記憶する 26 if( $i == 0){ 27 $cell_sql = array(); 28 foreach( $line as $v ){ 29 $cell_sql[] = sprintf("%s",$v); 30 } 31 } else { 32 //一行ずつ取り出したCSVの各セルをトリム関数を使ってSQL用に成形 33 $line_sql = array(); 34 foreach( $line as $v){ 35 $line_sql[] = sprintf("'%s'",formatting_to_sql($v)); 36 } 37 //まとめたセルをはき出してSQLを成形 38 $sql = sprintf( 39 'INSERT INTO table (%s) values (%s);' 40 ,mysql_real_escape_string(implode(',',$cell_sql)) 41 ,mysql_real_escape_string(implode(',',$line_sql)) 42 ); 43 44 //SQL実行 45 //... 46 } 47 //ループカウンタをインクリメント 48 $i++; 49 } 50 51 //ファイルを閉じる 52 fclose($fp);
投稿2015/04/09 14:08
編集2015/04/10 01:05総合スコア53
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/04/09 17:49
2015/04/09 17:58
2015/04/10 00:55
2015/04/10 01:03
2015/04/10 01:09
2015/04/10 01:29
2015/04/10 09:57
2015/04/10 09:59
2015/04/11 08:23
2015/04/11 18:19
2015/04/11 18:48
2015/04/13 01:57
0
具体的な情報がわからないため、原因を特定して回答することは難しいです。
ただ、CSVはダブルクォートで囲むことで強制的にテキストとして認識させることができますが、エクセルはそれでも数字のみのセルは数字と判別して先頭の0を省いて表示していた記憶があります。
CSVの作り方によっては先頭に0がついてしまうケースもあるかもしれません。
DB内に登録するスクリプトを用意したのですが
PHPMyAdminなどのツールではなく、ご自身でプログラムをご用意されたという認識でよろしいでしょうか。
ご自身でプログラムをご用意されていて、インポート用のプログラムを編集することが可能という前提で、以下に正規表現を用いたトリム用関数の例を挙げます。
①数字以外の文字を含む場合、そのまま返却
②全部数字の0だった場合には0を返却
③全部数字だが、0以外の数字が含まれる場合には先頭の0を削除して返却(複数ついていても一括削除)
これを、CSVの各要素に対して適用してみてください。
lang
1<?php 2 function trim_zero($v) { 3 if( preg_match('/[^\d]/',$v) ){ 4 //数字以外の文字を含む場合はそのまま返す 5 return $v; 6 } 7 if( preg_match('/^0+$/',$v) ){ 8 //テキストが全部0だったら0にして返す 9 return 0; 10 } else { 11 //テキストに0以外の数字があったら先頭の0を省いて返す 12 return intval(preg_replace('/^0*([1-9][0-9]*)$/','$1',$v,1)); 13 } 14 } 15 $v = '0010'; 16 echo trim_zero($v);
投稿2015/04/09 00:56
編集2015/04/09 00:59総合スコア53
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/04/09 01:39
2015/04/09 13:39
2015/04/09 14:09
0
UPDATEの場合はどのようなソースとなるのでしょうか?
INSERTとUPDATEをわけるためにPKでレコードが登録されているかどうかを調べるSQLをまずは流します。 ON DUPLICATE KEYを使ってINSERT文一回で済ませる方法もありますが、上記のベーシックなやり方をまずは例として以下に提示します。
コードは前回までに作ったものの修正版です。
主だった修正点は以下のとおり。
1.桁数の多い数字の場合INT型の上限を迎えるので、formatting_to_sqlはINTVALでINT型に直さないで返すようにしました。
2.SELECT文を最初に流してレコードの有無を確認し、INSERTとUPDATEに分かれてSQLを生成します。
lang
1<?php 2 function formatting_to_sql($v) { 3 //空白文字を除去 4 $v = trim($v); 5 6 if( preg_match('/[^\d]/',$v) ){ 7 //数字以外の文字を含む場合はテキストとして判別して文字コードを変えて返す 8 return mb_convert_encoding($v, "UTF-8", "SJIS"); 9 } 10 if( preg_match('/^0+$/',$v) ){ 11 //テキストが全部0だったら0にして返す 12 return 0; 13 } else { 14 //テキストが数字で0以外の数字があったら先頭の0を省いて返す 15 return preg_replace('/^0*([1-9][0-9]*)$/','$1',$v,1); 16 } 17 } 18 19 //CSVを読み込む 20 $fp = fopen('sample.csv','r'); 21 22 //一行ずつCSVからデータを取り出しつつループ 23 $i = 0; 24 while( $line = fgetcsv($fp) ){ 25 //ヘッダ行からセル名を記憶する 26 if( $i == 0){ 27 $cell_sql = array(); 28 $cell_primary = ''; 29 $cell_nums = 0; 30 foreach( $line as $k => $v ){ 31 if( $k == 0 ){ 32 $cell_primary = formatting_to_sql($v); 33 } 34 $cell_sql[] = formatting_to_sql($v); 35 $cell_nums++; 36 } 37 } else { 38 //一行ずつ取り出したCSVの各セルをトリム関数を使って記憶する 39 $line_sql = array(); 40 $line_primary = ''; 41 foreach( $line as $k => $v){ 42 if( $k == 0 ){ 43 $line_primary = formatting_to_sql($v); 44 } 45 $line_sql[] = sprintf("'%s'",formatting_to_sql($v)); 46 } 47 48 //PKで値が登録されているかを調べる参照用SQLを成形 49 $sql = sprintf("SELECT count(*) as cnt FROM table WHERE %s = '%s'" 50 ,mysql_real_escape_string($cell_primary) 51 ,mysql_real_escape_string($line_primary) 52 ); 53 54 //SELECT実行 55 //... 56 57 //挿入・更新用SQLを成形 58 if( $cnt == 0 ){ 59 //INSERTする 60 $sql = sprintf( 61 "INSERT INTO table (%s) values (%s);" 62 ,mysql_real_escape_string(implode(',',$cell_sql)) 63 ,mysql_real_escape_string(implode(',',$line_sql)) 64 ); 65 } else { 66 //UPDATEする 67 $sql_values = array(); 68 for($i=0; $i<$cell_nums; $i++){ 69 $sql_values[] = sprintf("%s = '%s'", $cell_sql[$i], $line_sql[$i]); 70 } 71 $sql = sprintf("UPDATE table SET %s WHERE %s = '%s'" 72 ,mysql_real_escape_string(implode(',',$sql_values)) 73 ,mysql_real_escape_string($cell_primary) 74 ,mysql_real_escape_string($line_primary) 75 ); 76 } 77 78 //SQL実行 79 //... 80 } 81 82 //ループカウンタをインクリメント 83 $i++; 84 } 85 86 //ファイルを閉じる 87 fclose($fp);
投稿2015/04/13 01:55
総合スコア53
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/04/13 02:36
2015/05/25 15:27
2015/05/27 01:53
2015/10/20 16:07
2015/10/21 02:01
2015/10/21 02:03
2015/10/29 14:16
0
(文字列のカラムも数値のカラムも、varcharとして設定)
なぜ数値のカラムもvarcharにしているのですか?
あと、MySQLにCSVをインポートするときに使っているツールは何ですか?
投稿2015/04/08 22:24
総合スコア971
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/04/09 01:31
2015/04/09 06:19
2015/04/09 13:11
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/04/09 01:33