我有一个数据库表,我需要将一堆记录导入。如果现有记录已经在数据库中,我不想覆盖现有记录,所以我先设置一个选择查询来检查是否有值,但显然行的导入速度太快跟上,因为我正在为我插入的每一行创建重复项。
我正在导入CSV文件。
这就是我正在做的事情(这是在Joomla系统中,因此一些代码和对象是特定于joomla的):
$fp = fopen(JPATH_ROOT.DS."tmp".DS.$filename, 'r');
//run insert query on each line of file
if(JRequest::getVar('importType')=="activated") {
while(!feof($fp)) {
while (($data = fgetcsv($fp, 1000, ",")) !== FALSE) {
if($this->checkUnique($data[0])) {
$this->runInsert2($data[0], $data[1], $data[2], $data[3]);
error_log("there is not already a code for ".$data[0]);
}
else {
error_log("there is already a code for ".$data[0]);
}
$row++;
}
}
}
FCLOSE($ FP);
这是checkUnique:
function checkUnique($vouchNum) {
$db =& JFactory::getDBO();
$query = "select COUNT(*) from arrc_Voucher where VoucherNbr=".$db->quote($vouchNum);
if(!$db->query()) error_log("error running unique check on ".$vouchNum." - " . $db->stderr());
$db->setQuery($query);
$count = $db->loadResult();
if($count>0) {
return false;
}
else {
return true;
}
}
这是runInsert2:
function runInsert2($vouchNum,$BalanceInit,$BalanceCurrent,$ActivatedDT) {
$rightNow = date('Y-m-d H:i:s');
$db =& JFactory::getDBO();
if($ActivatedDT <> "NULL") {
$activatedDTtmp = strtotime($ActivatedDT);
$activatedDT = date('Y-m-d H:i:s',$activatedDTtmp);
}
else {
$activatedDT = $rightNow;
}
$query = "insert into arrc_Voucher (VoucherNbr,BalanceInit, BalanceCurrent, ActivatedDT)
values (". $db->quote($vouchNum). ", ".$db->quote($BalanceInit).",".$db->quote($BalanceCurrent).",".$db->quote($activatedDT).")";
error_log("query: ".$query);
$db->setQuery($query);
if (!$db->query()) error_log("error inserting voucher number ". $vouchNum . "-" . $db->stderr());
}
我不知道我在哪里出错了,但是如果有人可以帮助我(或指出我避免重复的更好方向),我将非常感激。仅供参考,我们认为“独特”(VoucherNbr)的字段实际上并不是主键,或者在表结构中以任何方式标记为唯一,并且不可能。这是我们现在需要在编码端解决的问题。
答案 0 :(得分:2)
设置一个唯一约束并使用insert ignore
,这样你就永远不会有重复。
那就是可以忽略重复的行。
您不能在列上设置唯一键而不是需要保留唯一值的原因是什么?
另一种解决方案是在具有相同结构的单独表中导入数据。
create table arrc_buffer like arrc_Voucher
。
在每次导入之前截断此表。
然后你可以从这个缓冲区插入你的arrc_Voucher表。
1。 从缓冲区中删除arrc_Voucher中已有的所有行。
delete arrc_buffer b
from arrc_buffer b
inner join arrc_Voucher v on b.VoucherNbr = v.VoucherNbr;
然后将其余部分插入arrc_Voucher。
insert into arrc_Voucher
select * from arrc_buffer
除了这些导入之外,还有其他例程在arrc_Voucher中插入数据吗?
答案 1 :(得分:0)
如果您确实无法更改表,则可能必须检查重复项并在INSERT后删除它们,或者在检查现有行之前锁定表。您无法保证SELECT和INSERT语句之间不会发生INSERT。