2010-10-19 53 views
0

我有一個數據庫表,我需要導入一堆記錄。如果它們已經存在於數據庫中,我不想覆蓋現有記錄,所以我已經設置好了首先執行選擇查詢以檢查是否有值,但顯然行索引導入過快跟上,因爲我正在爲我插入的每一行創建重複項。如何在將行導入到mySQL之前檢查值是否唯一?

我正在導入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

您可以在一個查詢中插入所有內容,並通過DELETE FROM table刪除重複項WHERE ID IN(SELECT ID FROM表GROUP BY字段HAVING COUNT(field)> 2)' – Andrew 2010-10-19 23:03:38

+0

通常我在列上放置一個唯一約束,處理有人試圖添加副本時的錯誤。 – 2010-10-19 23:12:25

+0

@OMG Ponies - 是的,我們通常也對列有一個唯一的約束,但這是客戶的數據庫,他不希望對錶設計做任何更改。 – EmmyS 2010-10-20 00:42:12

回答

0

如果您確實無法更改表格,則可能需要檢查重複項並在INSERT後將其刪除,或在檢查現有行之前鎖定表格。您不能保證在您的SELECT和INSERT語句之間不發生INSERT。

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?

+0

+1。你可以INSERT在一個語句中,而不是首先運行DELETE,例如「INSERT INTO arrc_voucher SELECT x,y,z FROM arrc_buffer WHOU VoucherNbr NOT IN(SELECT VoucherNbr FROM arrc_voucher)」 – richaux 2010-10-20 09:21:40

+0

@richaux,select whereting not在()中很慢,我儘量避免這種情況。將它放在一個聲明中並不總是更好(更快)。有時候,我更喜歡在幾份報表中分工,因爲每個報表都可以運行得非常快,而且整個流程可以更順利。 – ceteras 2010-10-20 14:30:55

+0

是的,好點。也許一個'WHERE NOT EXISTS'? ......或幾個陳述;) – richaux 2010-10-20 20:03:30

相關問題