2009-10-31 6 views
5

Ich analysiere einen JSON-Feed routinemäßig und muss nur die neuesten Benutzer aus dem Feed einfügen und vorhandene Benutzer ignorieren.SQL: Nur neue Zeilen/Datensätze in eine Tabelle einfügen?

Ich denke, was ich brauche, ist ON DUPLICATE KEY UPDATE oder INSERT IGNORE auf einiger Suche basierte, aber ich bin nicht ganz sicher, weshalb ich frage - so zum Beispiel:

users 
1  John 
2  Bob 

Teil JSON:

{ userid:1, name:'John' }, 
{ userid:2, name:'Bob' }, 
{ userid:3, name:'Jeff' } 

Von diesem Feed möchte ich nur Jeff einfügen. Ich könnte eine einfache Schleife durch alle Benutzer tun und eine einfache SELECT-Abfrage machen und sehen, ob die Benutzer-ID bereits in der Tabelle ist, wenn nicht, mache ich einen INSERT, aber ich vermute, dass es keine effiziente und praktische Methode ist.

Übrigens verwende ich Zend_Db für die Datenbank-Interaktion, wenn jemand eine bestimmte Antwort liefern möchte :) Ich habe keine Probleme mit einer allgemeinen strategischen Lösung.

Antwort

5

Die ON DUPLICATE KEY UPDATE Alternative können Sie das Update vs. Insert Entscheidung auf die Datenbank verweisen:

INSERT INTO table (userid, name) VALUES (2, 'Bobby'); 
    ON DUPLICATE KEY UPDATE name = 'Bobby'; 

würde das Namensfeld aktualisieren, um 'Bobby', wenn ein Eintrag mit Benutzer-ID 2 bereits vorhanden ist.

Sie es als Alternative zu den INSERT IGNORE verwenden können, wenn Sie einen nicht wirksamen Betrieb zum UPDATE liefern:

INSERT INTO table (userid, name) VALUES (2, 'Bobby'); 
    ON DUPLICATE KEY UPDATE name = name; 

Dies würde nichts tun, wenn Benutzer-ID 2 bereits vorhanden ist, so die Warnung und das Schlucken von anderen Fehler zu vermeiden Sie würden erhalten, wenn Sie INSERT IGNORE verwenden.


Eine weitere Alternative wäre REPLACE sein:

REPLACE INTO table (userid, name) VALUES (2, 'Bobby'); 

Dies würde einen normalen Einsatz tun, wenn die Benutzer-ID 2 existiert noch nicht. Wenn es existiert, löscht es zuerst den alten Eintrag und fügt dann einen neuen ein.


Beachten Sie, dass beide Versionen MySQL-spezifische Erweiterungen für SQL sind.

0

In der Schleife können Sie zuerst eine Aktualisierung durchführen, wenn keine Zeile betroffen ist, bedeutet dies, dass es sich um einen neuen Eintrag handelt. Verfolgen Sie diese "fehlgeschlagenen Updates" und fügen Sie sie als neue Einträge ein.

Ich bin nicht vertraut mit Zend_Db, aber ich nehme an, es kann zurückgeben, ob ein Update die Anzahl der Zeilen beeinflusst.

+0

Irgendwie falsch verstehe ich die Frage nach der Notwendigkeit, vorhandene Benutzer zu aktualisieren, falls sie gefunden werden, andernfalls als neue einfügen. well ... down-voting –

2

Sie müssen Benutzer-ID als primäre oder UNIQUE Schlüssel definieren und wie etwas verwenden:

INSERT IGNORE INTO table (userid, name) VALUES (2, 'Bob'); 

Wenn der Benutzer-ID 2 bereits vorhanden ist, wird es ignoriert und auf den nächsten Einsatz bewegen.

Sie können ON DUPLICATE KEY UPDATE auch für Ihr Tabellenschema verwenden. Eine andere Alternative könnte die Verwendung der REPLACE INTO-Syntax sein.

REPLACE INTO table (userid, name) VALUES (2, 'Bob'); 

Dies wird versuchen, einfügen, wenn der Datensatz bereits es wird DELETE existiert, bevor es wieder eingesetzt wird.

+0

Wird 'INSERT IGNORE' in Zend_Db unterstützt? –

+0

Ehrlich, NoFid. –

+0

Der 'IGNORE' bewirkt, dass die db-Engine Warnungen anstelle von Fehlern ausgibt, so dass die Ausführung der Abfrage nicht gestoppt wird. Ein Nachteil dieses Ansatzes besteht darin, dass * jeder * aufgetretene Fehler ignoriert wird und nicht nur ein doppelter Schlüssel, sondern auch eine Warnung wird. –

4

Für Zend Framework, was ich tue, ist ein try/catch der Insert-Anweisung und weitere Maßnahmen ergreifen auf dem Ausnahmecode basierten:

class Application_Model_DbTable_MyModel extends Zend_Db_Table_Abstract 

    public function insert($aData, $bIgnore = false) 
    { 

     try 
     { 
      $id = parent::insert($aData); 
     } 
     catch(Zend_Db_Statement_Mysqli_Exception $e) 
     { 
      // code 1062: Mysqli statement execute error : Duplicate entry 
      if($bIgnore && $e->getCode() == 1062) 
      { 
       // continue; 
      } 
      else 
      { 
       throw $e; 
      } 
     } 
     return !empty($id) ? $id : false; 
    } 
} 
+0

Sie müssen $ bIgnore wegen strenger Standards aufgeben: Deklaration von Your_Model :: insert() sollte kompatibel sein mit Zend_Db_Table_Abstract :: insert (array $ data) in ... – bensiu

1

Meine Lösung:

/** 
* Perform an insert with the IGNORE word 
* 
* @param $data array 
* @return number the number of rows affected 
*/ 
public function insertIgnore(array $data) 
{ 
    // Start of query 
    $sql = sprintf("INSERT IGNORE INTO %s (", $this->getAdapter()->quoteIdentifier($this->info('name'))); 
    // Retrieve column identifiers 
    $identifiers = array_keys($data); 
    foreach ($identifiers as $key => $value) { 
     // Quote identifier 
     $identifiers[$key] = $this->getAdapter()->quoteIdentifier($value); 
    } 
    // Concat column identifiers 
    $sql .= implode(', ', $identifiers); 
    $sql .= ") VALUES ("; 
    foreach ($data as $key => $value) { 
     // Quote values 
     $data[$key] = $this->getAdapter()->quote($value); 
    } 
    // Concat values identifiers 
    $sql .= implode(', ', $data); 
    $sql .= ")"; 
    // Process the query 
    return $this->getAdapter()->query($sql)->rowCount(); 
}