2017-08-23 75 views
1

我正在使用三表結構來處理多對多關係。我有一張有人名單的表格,另一張表格有一個項目清單。有時候多的人有相同的項目,有時倍數項目鏈接到同一個人,所以我設置如下表結構:在項目已存在時更新中間表時出現問題

CREATE TABLE people (
id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, 
fname varchar(128) NOT NULL, 
lname varchar(128) NOT NULL, 
); 

CREATE TABLE items (
id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, 
name varchar(128) NOT NULL UNIQUE, 
); 

的UNIQUE防止項目名稱重複從。

CREATE TABLE people_items (
pid int(11) NOT NULL, 
iid int(11) NOT NULL, 
FOREIGN KEY (pid) REFERENCES people(id) 
ON UPDATE CASCADE 
ON DELETE CASCADE 
FOREIGN KEY (iid) REFERENCES items(id) 
ON UPDATE CASCADE 
ON DELETE CASCADE 
); 

這使我可以將多個項目鏈接到多個人,反之亦然。它也允許我從中間表中刪除不必要的記錄。

只要輸入一個新項目,所有工作都會正常工作,但是如果輸入了一個現有項目,即使人員表是,中間表也不會更新。我也沒有得到任何錯誤。

項目是一個逗號分隔的文本條目,它們被分解並放入$items中。

首先我插入任何新項目和檢索ID:

for ($i=0;$i<count($items);$i++){ 
$sql="INSERT IGNORE INTO items (name) VALUES (?);"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('s',$items[$i]); 
$stmt->execute(); 
$itemid=$stmt->insert_id; 

如果返回一個新的ID執行以下操作:

if ($itemid){ 
$sql="INSERT INTO people_items (pid,iid) VALUES (?,?);"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('ii',$peopleid,$itemid);//the $peopleid is acquired the same way that the $itemid is acquired above 
$stmt->execute(); 
} 

到這裏,一切都運行得很好。此時,如果現有的項目已經在項目表中,那麼我的中間表不會更新。然而,人員表更新得很好,而且物品表不需要更新,因爲它已經包含了物品。

這裏是我嘗試了兩種不同的方法來更新中間表。

首先我保持選擇和插入查詢分開。

elseif(!$itemid){ 
$sql="SELECT id,name FROM items WHERE name=?;"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('s',$items[$i]); 
$stmt->execute(); 
$stmt->store_result(); 
$stmt->bind_result($iid,$name); 
$stmt->fetch(); 
$sql="INSERT INTO people_items (pid,iid) VALUES (?,?);"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('ii',$pid,$iid); 
$stmt->execute(); 
} 

這裏是我也不會更新中間表的另一種方法:

elseif(!$itemid){ 
$sql="INSERT INTO people_items (pid, iid) SELECT id,name FROM items WHERE name IN (?);"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('s',$items[$i]); 
$stmt->execute(); 
} 

我在做什麼錯?

回答

0

對不起,我沒有得到更快,但我已經弄清楚,並在此期間忙於工作。我想我會提供答案,以防將來有人遇到同樣的問題。無論如何,這個問題是與我的SQL查詢。

在那裏我有這樣的:

elseif(!$itemid){ 
$sql="INSERT INTO people_items (pid, iid) SELECT id,name FROM items WHERE name IN (?);"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('s',$items[$i]); 
$stmt->execute(); 
} 

我應該有這樣的:

elseif(!$itemid){ 
$sql="INSERT INTO people_items (pid,iid) VALUES (?,(SELECT id FROM items WHERE name IN (?)));"; 
$stmt=$conn->prepare($sql); 
$stmt->bind_param('ss',$peopleid,$items[$i]); 
$stmt->execute(); 
} 
0

這是因爲您使用的是INSERT IGNORE,所以如果該項目已經存在,它將不會插入任何內容,並且您將得到0或上次成功插入的ID作爲ID(per the docs)。所以你需要檢查的是受影響的行數。如果它是0,那麼它被忽略,你可以從數據庫中獲得SELECT。如果它不是0,那麼你可以安全地插入最後一個ID。

for ($i=0;$i<count($items);$i++){ 
    $sql="INSERT IGNORE INTO items (name) VALUES (?);"; 
    $stmt=$conn->prepare($sql); 
    $stmt->bind_param('s',$items[$i]); 
    $stmt->execute(); 
    $itemid=$stmt->insert_id; 
    $affected_rows = $stmt->affected_rows; 
    if ($affected_rows !== 0) { 
     // insert 
    } 
    else { 
     // select and insert 
    } 
} 

旁註:

要插入在一個循環中的項目的方式是可怕的性能,特別是如果DB是不是在相同的主機服務器(想到要去超市:DO你去N次,單獨獲得每件物品,或者你只是去一次並得到你的N件物品?)。你應該做的是在一個查詢中插入所有的元素。很明顯,這不是你的情況,因爲你的ID和什麼不是,但你可以閱讀關於這個here開始。

相關問題