2017-08-23 30 views
1

Ich verwende eine Struktur mit drei Tabellen, um eine Viele-zu-Viele-Beziehung zu behandeln. Ich habe eine Tabelle mit einer Liste von Personen und eine andere mit einer Liste von Elementen. Manchmal haben mehrere Personen die gleiche Position und manchmal Multiples Artikel auf die gleiche Person verknüpft ist, so dass ich die folgende Tabellenstruktur aufgebaut:Problem beim Aktualisieren einer Zwischentabelle, wenn ein Element bereits existiert

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, 
); 

Das UNIQUE verhindert den Namen des Elements zu wiederholen.

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 
); 

Dadurch kann ich mehrere Elemente mit mehreren Personen verknüpfen und umgekehrt. Es erlaubt mir auch, unnötige Datensätze aus der Zwischentabelle zu löschen.

Alles funktioniert gut, solange ein neues Element eingegeben wird, aber wenn ein vorhandenes Element eingegeben wird, wird die Zwischentabelle nicht aktualisiert, obwohl die People-Tabelle ist. Ich bekomme auch keine Fehler.

Elemente sind ein durch Kommas getrennter Texteintrag, die in $items aufgelöst und in eine niedrigere Position gebracht werden.

Zuerst habe ich einfügen alle neuen Produkte und rufen Sie die 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; 

Wenn eine neue ID wird wie folgt ausgeführt zurückgegeben wird:

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(); 
} 

Bis hierher alles gut funktioniert. Wenn sich ein vorhandenes Element bereits in der Elementtabelle befindet, wird an dieser Stelle meine Zwischentabelle nicht aktualisiert. Die People-Tabelle wird jedoch problemlos aktualisiert, und die Elementtabelle muss nicht aktualisiert werden, da sie bereits das Element enthält.

Hier habe ich zwei verschiedene Ansätze ausprobiert, um die Zwischentabelle zu aktualisieren.

Zuerst hielt ich die Auswahl und Einfügen von Abfragen getrennt.

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(); 
} 

Hier ist meine alternative Ansatz, der auch nicht die Zwischentabelle nicht aktualisiert:

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(); 
} 

Was mache ich falsch?

Antwort

0

Entschuldigung, ich bin nicht früher dazu gekommen, aber ich habe es herausgefunden und war in der Zwischenzeit mit der Arbeit beschäftigt. Ich denke, ich würde die Antwort geben, falls jemand in Zukunft dasselbe Problem hat. Wie auch immer, das Problem war mit meiner SQL-Abfrage.

Wo ich dies hatte:

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(); 
} 

ich das gehabt haben sollte:

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

Das liegt daran, dass Sie INSERT IGNORE verwenden. Wenn das Element also bereits existiert, wird nichts eingefügt, und Sie erhalten entweder 0 oder die ID des letzten erfolgreichen Einfügens als ID (per the docs). Was Sie also überprüfen müssen, ist die Anzahl der betroffenen Zeilen. Wenn es 0 ist, dann wurde es ignoriert und Sie können SELECT es aus der DB. Wenn es nicht 0 ist, können Sie die letzte ID sicher einfügen.

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 
    } 
} 

Nebenbei bemerkt:

Die Art und Weise Sie die Elemente in einer Schleife einfügen, ist schrecklich für die Leistung, vor allem, wenn die DB nicht in dem gleichen Host wie der Server ist (denken Sie an in den Supermarkt gehen: do Du gehst n mal und holst jedes Item selbst, oder gehst du nur einmal und holst dir deine N Items?). Was Sie tun sollten, ist das Einfügen aller Elemente in einer Abfrage. Klar ist es nicht so klar in deinem Fall, da du die IDs kennst und was nicht, aber du kannst darüber here lesen, um loszulegen.

Verwandte Themen