2009-10-31 14 views
5

Sto analizzando routinariamente un feed JSON e devo inserire solo i nuovi utenti dal feed e ignorare gli utenti esistenti.SQL: inserire solo nuove righe/record in una tabella?

Penso che quello che ho bisogno è ON DUPLICATE KEY UPDATE o INSERT IGNORE sulla base di qualche ricerca ma non sono del tutto sicuro che è questo che sto chiedendo - così per esempio:

users 
1  John 
2  Bob 

JSON parziale:

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

Da questo feed voglio solo inserire Jeff. Potrei fare un semplice ciclo attraverso tutti gli utenti e fare una semplice query SELECT e vedere se l'id utente è già nella tabella, altrimenti faccio un INSERT, tuttavia sospetto che non sarà un metodo efficiente e pratico.

A proposito, sto utilizzando Zend_Db per l'interazione del database se qualcuno vorrebbe soddisfare una risposta specifica :) Non mi dispiace però una soluzione strategica generica.

risposta

5

Il ON DUPLICATE KEY UPDATE alternativa consente di riferimento l'aggiornamento vs decisione inserto al database:

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

sarebbe aggiornare il campo del nome di 'Bobby', se una voce con userid 2 esiste già.

È possibile utilizzare come alternativa al INSERT IGNORE se si fornisce un operazione noneffective alla UPDATE:

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

Questo sarebbe non fare nulla se userid 2 già esistente, evitando così l'avvertimento e la deglutizione di altri errori si otterrebbe quando si utilizza INSERT IGNORE.


Un'altra alternativa sarebbe REPLACE:

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

Questo farebbe un inserto normale se l'userid 2 non esiste ancora. Se esiste, eliminerà prima la vecchia voce e poi ne inserirà una nuova.


Attenzione, entrambe le versioni sono estensioni specifiche di SQL per SQL.

0

Nel ciclo, è possibile eseguire prima un aggiornamento, se nessuna riga interessata significa che è una nuova voce. Tieni traccia di questi "aggiornamenti non riusciti", quindi inseriscili come nuove voci.

Non ho familiarità con Zend_Db ma presumo che possa restituire se un aggiornamento ha interessato quante righe.

+0

In qualche modo ho letto male il domanda per la necessità di aggiornare gli utenti esistenti se trovati, altrimenti inserirli come nuovi. beh ... down-vote –

2

è necessario definire userid come chiave primaria o univoca e usare qualcosa come:

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

Se l'ID utente 2 esiste già ignorerà e passare al successivo inserimento.

È inoltre possibile utilizzare ON DUPLICATE KEY UPDATE sullo schema della tabella. Un'altra alternativa potrebbe essere l'uso della sintassi REPLACE INTO.

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

Questo proverà a inserire, se il record esiste già sarà eliminarlo prima di inserirlo di nuovo.

+0

È 'INSERT IGNORE' supportato in Zend_Db? –

+0

Onestamente, NoFId. –

+0

"IGNORE' farà sì che il motore db emetta avvisi anziché errori, quindi l'esecuzione della query non si interromperà. Un inconveniente di questo approccio è che * qualsiasi * errore riscontrato verrà ignorato/trasformato in avviso, non solo una chiave duplicata. –

4

per Zend Framework, quello che faccio è un try/catch della dichiarazione dell'inserto e intraprendere ulteriori azioni in base al codice di eccezione:

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

devi rinunciare a $ bIgnore a causa di Strict Standards: Dichiarazione di Your_Model :: insert() dovrebbe essere compatibile con Zend_Db_Table_Abstract :: insert (array $ data) in ... – bensiu

1

La mia soluzione:

/** 
* 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(); 
} 
Problemi correlati