MySQLの質問

CSVのデータをMySQLに移そうと思ったのですが連続してデータを挿入する方法がわかりません。
for文でSQLを発行しようとしても1行で止まってしまいます。

処理の大まかな流れは
CSVファイル読み込み
foreach{
 DBにコネクト
 insert文
 DB切断


こんな感じです。
DBコネクトと切断をforの外に出しても結果は同じでした・・・

言語はperlが好ましいですがPHPでもかまいません。

回答の条件
  • 1人5回まで
  • 登録:2006/04/03 18:19:01
  • 終了:2006/04/03 20:39:30

回答(5件)

id:taknt No.1

きゃづみぃ回答回数13539ベストアンサー獲得回数11982006/04/03 18:25:31

ポイント20pt

一般的に考えられるロジックは、以下のとおりです。

DBにコネクト(トランザクション開始)

CSVファイル オープン

ループ開始

CSVファイルから1行目を読み込み

最終行なら 終了処理へ

INSERT文

ループ開始へ戻る

終了処理

コミット発行

DB切断

エラー時

ロールバック

DB切断

id:pipi_n

ロジックはその通りなんですよね。

そのロジックでも試してみたのですがダメでした・・・

2006/04/03 18:43:56
id:inokuni No.2

いのくに回答回数1343ベストアンサー獲得回数212006/04/03 18:36:27

ポイント50pt

「load data infile」という便利なSQL文の使用を検討されてみてはいかがですか?

http://dev.mysql.com/doc/refman/4.1/ja/load-data.html

load data infile 'ファイル名' into table テーブル名 fields terminated by '区切り文字' lines terminated by '改行記号';

id:pipi_n

おぉ!そんな命令があるのですね!

試してみます。

試した結果・・・うまくいかなかったです・・・

下記のソースで「接続失敗2」で止まってしまいます。

use DBI;

print "Content-type: text/html\n\n";

print "<html>";

print "接続
\n";

# DBに接続

$db = DBI->connect("DBI:mysql:DB名:ホスト名","ID","PASS");

if(!$db){

print "接続失敗1\n";

exit;

}

$sth = $db->prepare("load data infile 'in.txt' into table test fields terminated by ',' lines terminated by '\r\n'");

if(!$sth->execute){

print "接続失敗2\n";

exit;

}

# ステートメントハンドルクリア

$sth->finishi;

# DB切断

$db->disconnect;

print "処理終了

\n";

2006/04/03 19:16:08
id:kuippa No.3

くいっぱ回答回数1030ベストアンサー獲得回数132006/04/03 18:45:44

ポイント20pt

PHPですが、こんな感じです。

トランザクションを使用していませんが、つかうなら、takntさんがご指定のような位置がベストかと思います。


手元にあったcsvのアッププログラムから共通関数やらなにやらを消して簡略化したものですが…

<?php
$tmp_file_path = $_FILES['upfile']['tmp_name'];
if ($tmp_file_path == "") {
	die("ファイルが指定されていません");
}
// DB Connect
gfDBConn($conn);
$handle = fopen($tmp_file_path, "r");
if ($handle) {
	while (!feof($handle)) {
		$buffer = fgets($handle, 4096);
		$pieces = explode(",", $buffer);
		if ($pieces[1] != "" ) {
			// DB Insert
			fInsStockMst($pieces[1] ,$pieces[3] ,$pieces[2]);
		}
	}
	fclose($handle);
}
// MySQL 切断
mysql_close($conn);
print("完了<br><a href=./index.php>もどる</a>");
// DB接続
function gfDBConn(&$conn) {
	global $pcDBname,$pcMySqlUser,$pcMySqlPass,$pcDatenbankname;
	$conn = mysql_connect($pcDBname,$pcMySqlUser,$pcMySqlPass);
	mysql_select_db($pcDatenbankname,$conn);
}
// 登録処理
function fInsStockMst($stock_cd ,$stock_nm ,$market_cd) {
	global $conn;
	$sSQL = "";
	$sSQL .= "insert into stock_mst (";
	$sSQL .= "	stock_cd,";
	$sSQL .= "	stock_nm,";
	$sSQL .= "	market_cd,";
	$sSQL .= "	upddate,";
	$sSQL .= "	insdate";
	$sSQL .= ") values (";
	$sSQL .= " '".gfFixUpStr($stock_cd)."',";
	$sSQL .= " '".gfFixUpStr($stock_nm)."',";
	$sSQL .= " '".gfFixUpStr($market_cd)."',";
	$sSQL .= "now(),";
	$sSQL .= "now()";
	$sSQL .= ") ";
	$sSQL .= "ON DUPLICATE KEY UPDATE ";
	$sSQL .= "	market_cd4 = if(market_cd3 <> '','".gfFixUpStr($market_cd)."',''),  ";
	$sSQL .= "	market_cd3 = if(market_cd2 <> '','".gfFixUpStr($market_cd)."',''),  ";
	$sSQL .= "	market_cd2 = if(market_cd <> '','".gfFixUpStr($market_cd)."','')   ";
	$res = gfGetDBRs($sSQL, $conn);
}
// 入力を表示文字列からDB格納型へ
function gfFixUpStr($getstr,$rnflg=0,$maxlen=0) {
	// サニタイズやらなにやら
	$str = $getstr;
	return $str;
}
?>
id:pipi_n

ソースまで書いて頂きありがとうございます。

しかし「PHPでもかまいません」とは書いたものの、PHPはあまり得意ではないのでkuippaさんが書いてくれたソースがいまいち理解できないでいます。

inokuniさんが教えてくれた命令で試して、どうしてもダメならkuippaさんのソースを解析して試してみようと思います。

2006/04/03 19:45:14
id:inokuni No.4

いのくに回答回数1343ベストアンサー獲得回数212006/04/03 19:21:46

ポイント50pt

$sth = $db->prepare("load data infile 'in.txt' into table test fields terminated by ',' lines terminated by '\r\n'");

in.txt の位置を相対パスではなく、絶対パスで記述する必要があります。

例: /home/user001/in.txt

あと、そのファイルがサーバ側にあるのか、クライアント側にあるのか?

クライアント側にあるのであれば、

load data local infile "/home/user001/in.txt" ...

と「LOCAL」を付与しなければなりません。

id:pipi_n

in.txtは同一サーバ上にあります。

絶対パスで指定してlocalも付けたり消したりを試してみたのですがダメでした。

「接続失敗2」で止まってしまいます。

ちなみにバージョンはMySQL 4.0.24です。

load data infile が使えないバージョンだったら笑い話にもならないですが・・・

$sth = $db->prepare("load data infile '/usr/home/・・・/in.txt' into table test fields terminated by ',' lines terminated by '\n'");

2006/04/03 19:45:31
id:inokuni No.5

いのくに回答回数1343ベストアンサー獲得回数212006/04/03 20:01:00

ポイント50pt

私の場合は下記のSQL文でうまくいっています。

LOAD DATA LOCAL INFILE "/home/user001/in.txt" INTO TABLE testtable FIELDS TERMINATED BY ',' ENCLOSED BY '"' (field1, field2, field3, field4);

各フィールドの型とか合ってるんでしょうかね?

あとは、エラーの原因を突き止めるしかないと思うので、

$dbh = DBI->connect($data_source, $username, $password) || die $DBI::errstr;

$sth = $dbh->prepare("load data infile '/usr/home/・・・/in.txt' into table test fields terminated by ',' lines terminated by '\n'")|| die $dbh->errstr;

$rv = $sth->execute || die $sth->errstr;

という感じで、errstrを参照してみてください。

id:pipi_n

perlからではなく、phpMyAdminからSQLを実行してみたらできました!

なぜperlからはできないのでしょう・・・

パスが通っていないのかな?う~ん・・・

ということで今回はphpMyAdminからできたからOKとしますが、今後のこともあるのでerrstrで原因を追及してみたいと思います。

(使い方わからないから調べなきゃ)

inokuniさん、ほんとうにありがとうございました!

2006/04/03 20:37:32
  • id:bonlife
    Perlから実行する場合とphpMyAdminから実行する場合では、OSのユーザが違い、読み込もうとしているファイルへのアクセス権限が異なるのではないでしょうか。
    http://www.mysql.gr.jp/mysqlml/mysql/msg/8344
    こちらに似たような問題で困っている例があり、回答者はディレクトリやファイルの権限を問題視しています。
    (結局、解決したかどうかが分からないやりとりなので、読んでもスッキリしないのですが。)
  • id:pipi_n
    なるほど、アクセス権限も考えられますね。
    参考サイトは本人は解決したみたいですが、なんかすっきりしませんね・・・

    権限からも調べてみます。
    ありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません