我需要上传一个大的CSV到MySQL,如果上传中断,我必须从我停止的地方开始,没有重复的条目。如果进程中断,那么它应该从我自动结束的地方重新启动(即:如果在123个条目之后上传breaK,那么它在下一次运行时应该从124个恢复)
CSV文件格式:
latitude longitude
6.5486 72.456
4.2186 74.466
5.5486 82.956
我只需要一个纬度和经度相同的条目,目前我正在使用下面的代码(正在工作),但如果上传中断,我不知道如何从中断点开始。
<?php
error_reporting(0);
require("connection.php");//connect to the database
if ($_FILES[csv][size] > 0){
//get the csv file
$file = $_FILES[csv][tmp_name];
echo $fname = $_FILES['csv']['name'];
echo $ftype = end(explode('.', strtolower($fname)));
if($ftype=="csv"){
$handle = fopen($file,"r");
//loop through the csv file and insert into database
do {
if ($data[0]) {
$latitude=$data[0];
$longitude=$data[1];
$location1=$data[2];
$location2=$data[3];
$location3=$data[4];
$sql = "SELECT * FROM latitude_longitude WHERE latitude ='$latitude' AND longitude='$longitude' ";
$result=mysql_query($sql);
if( mysql_num_rows($result) > 0){
mysql_query("UPDATE latitude_longitude SET latitude = '$latitude',longitude = '$longitude',location1='$location1', location2='$location2',location3='$location3',status=status+1 WHERE latitude = '$latitude' AND longitude = '$longitude'");
}
else{
mysql_query("INSERT INTO latitude_longitude (latitude, longitude, location1, location2, location3, status, date) VALUES
(
'".addslashes($data[0])."',
'".addslashes($data[1])."',
'".addslashes($data[2])."',
'".addslashes($data[3])."',
'".addslashes($data[4])."',
'1',
CURRENT_TIMESTAMP
)
");
}
}
} while ($data = fgetcsv($handle,1000,",","'"));
//redirect
header('Location:GeoLocation.php?success=1'); die;
}else{
header('Location:GeoLocation.php?success=2'); die;
}
}
?>
谢谢你提前帮忙。
在经度、纬度上创建唯一密钥
然后你可以使用下面的
LOAD DATA LOCAL INFILE 'c:''temp''filename.csv'
replace
INTO TABLE table_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY ''r'n'
IGNORE 1 LINES
(@col1,@col2,@col3)
set
column1 = @col1,
column2= @col2,
column3= @col3;
这将替换重复的long、lat并插入新的
注意:强烈建议您使用PDO,因为mysql_*
功能正在逐步淘汰。你也可以摆脱所有的addslashes()
!
对于插入,您可以这样进行:
保持会话有关CSV 的一些信息
$import = array(
'current' => 0,
'total' => 0, // Estimated
'begun' => 0,
'fpos' => 0,
'flen' => 0, // Total CSV file size
'errors' => 0,
);
并创建一个UNIQUE INDEX,覆盖您不希望重复的字段(CREATE UNIQUE INDEX ...
)
从CSV:导入时
- open $csv file
- fseek() the file to the $session['fpos'] offset
- MySQL set AUTOCOMMIT to off;
- MySQL BEGIN WORK;
- Get current time plus 10 seconds into $ttl
- loop
- read one record using, say, fgetcsv()
- try
- insert into the DB using INSERT IGNORE
- catch PDO error
- MySQL ROLLBACK, $session['errors']++ and immediately die().
- is time() equal or above $ttl? If so, break
- update the session object, set its 'errors' to 0, put fpos() of $csv file into it
- MySQL COMMIT;
- Your ETA is $session['begun'] + (time()-$session['begun'])*($session['fpos']/$session['flen']).
使用上述方法,每次迭代将花费10秒以上的时间。
如果插入操作顺利,则新会话将包含从何处开始的下一个文件偏移量。
如果出现一些错误,整个事务块将回滚,并且它将像从未启动一样。您可以跟踪连续的错误(它们可能意味着CSV中出现了问题)。
您可以这样做,并将会话对象作为JSON返回。然后,您可以通过jQuery $.get()
导入调用上述脚本的CSV,并使用它来更新进度条。您将能够计算整个过程的预期到达时间:
importing [############## ] 48%, 32m 15s left
这意味着"上传"页面必须将CSV文件移动到临时目录中,并立即显示将显示进度条的HTML。然后这个HTML(和Javascript)将负责上传继续
还有一些上传库,如PLupload,它们以"块"的形式上传文件,并显示自己的进度条。由于通常网络上传比MySQL上传慢,因此一次上传一个块非常方便。每个区块中的最后一个CSV记录可能会被截断,因此需要进行某种检查,并且必须保存该区块的"片段"并将其附加到下一个区块以重建记录。
plupload方法的优点是,MySQL导入显然不需要任何时间——上传完成后,即使是非常大的文件,数据也可用。您将它放入一个具有临时名称的表中(而不是MySQL临时表,否则您将面临数据丢失的风险),当上传完成时,您只需原子化地重命名该表。