2009-10-31 26 views
5

Rutynowo analizuję źródło json i muszę wstawiać tylko najnowszych użytkowników z kanału i ignorować istniejących użytkowników.SQL: Wstawianie tylko nowych wierszy/rekordów do tabeli?

myślę co muszę to ON DUPLICATE KEY UPDATE lub INSERT IGNORE oparty na poszukiwaniach, ale nie jestem pewien, dlatego pytam - tak na przykład:

users 
1  John 
2  Bob 

Częściowa JSON:

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

Z tego kanału chcę wstawić tylko Jeffa. Mogłem wykonać prostą pętlę przez wszystkich użytkowników i wykonać proste zapytanie SELECT i sprawdzić, czy identyfikator użytkownika jest już w tabeli, jeśli nie, wykonuję INSERT, jednak podejrzewam, że nie będzie to skuteczna i praktyczna metoda.

Nawiasem mówiąc, używam Zend_Db do interakcji z bazą danych, jeśli ktoś chciałby podać konkretną odpowiedź :) Nie mam jednak nic wspólnego z ogólnym rozwiązaniem strategicznym.

Odpowiedz

5

ON DUPLICATE KEY UPDATE alternatywa pozwala skierować aktualizację vs. decyzji insert do bazy danych:

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

by zaktualizować pole nazwy na „Bobby”, jeśli wpis z identyfikatora 2 już istnieje.

Można go używać jako alternatywa do INSERT IGNORE jeśli dostarczy noneffective operację UPDATE:

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

to zrobi nic, jeśli userid 2 już istnieje, unikając w ten sposób ostrzegania i połykanie innych błędów otrzymasz przy użyciu INSERT IGNORE.


Inną alternatywą byłoby REPLACE:

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

byłoby to zrobić normalną wkładkę jeśli userid 2 jeszcze nie istnieje. Jeśli istnieje, usunie stary wpis, a następnie wstawi nowy.


Należy pamiętać, że obie wersje są specyficznymi dla MySQL rozszerzeniami SQL.

0

W pętli można najpierw wykonać aktualizację, jeśli żaden wiersz nie dotyczy, oznacza to, że jest to nowy wpis. Śledź te "nieudane aktualizacje", a następnie wstaw je jako nowe wpisy.

Nie znam Zend_Db, ale zakładam, że może zwrócić, czy aktualizacja wpłynęła na liczbę wierszy.

+0

Jakoś misread pytanie o potrzebę aktualizacji istniejących użytkowników, jeśli zostanie znaleziony, w przeciwnym razie wstaw jako nowy. dobrze ... w dół głosował –

2

Musisz określić identyfikator użytkownika jako podstawowy lub unikalny klucz i użyć czegoś takiego:

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

Jeśli userid 2 już istnieje to zignorować i przejść do następnej wkładki.

Można również użyć NA DUPLIKATU NA KLAWISZ AKTUALIZACJI na schemacie stołu. Inną alternatywą może być użycie składni REPLACE INTO.

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

To spróbuje wstawić, jeśli już istnieje zapis będzie go usunąć przed włożeniem go ponownie.

+0

Czy w Zend_Db obsługiwane jest 'INSERT IGNORE'? –

+0

Szczerze, NoFId. –

+0

'IGNORE' powoduje, że silnik db wydaje ostrzeżenia zamiast błędów, więc wykonanie zapytania nie zostanie zatrzymane. Wadą tego podejścia jest to, że * any * napotkany błąd zostanie zignorowany/obrócony do ostrzeżenia, a nie tylko duplikatu klucza. –

4

Dla Zend Framework, co robię to try/catch z INSERT i podjęcia dalszych działań w oparciu o kod wyjątek:

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

musisz zrezygnować z $ bIgnore z powodu ścisłych standardów: Deklaracja twojego_Modelu :: insert() powinna być zgodna z Zend_Db_Table_Abstract :: insert (array $ data) w ... – bensiu

1

Moje rozwiązanie:

/** 
* 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(); 
} 
Powiązane problemy