2009-10-31 14 views
5

私はjsonフィードを定期的に解析しており、フィードから最新のユーザーのみを挿入して既存のユーザーを無視する必要があります。SQL:新しい行/レコードのみをテーブルに挿入しますか?

は、私はいくつかの検索に基づいてON DUPLICATE KEY UPDATEまたはINSERT IGNOREで必要なものだと思うが、私は私が求めている理由である、非常にわからない - 例えばので:

users 
1  John 
2  Bob 

部分JSON:

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

このフィードから、私はJeffを挿入したいだけです。単純なループをすべてのユーザーから実行し、単純なSELECTクエリを実行して、ユーザーIDが既にテーブルに入っているかどうかを確認します。INSERTを実行しないと、効率的で実用的な方法ではないでしょう。

ちなみに、誰かが特定の回答に対応したい場合は、データベースのやりとりにZend_Dbを使用しています。私は一般的な戦略的なソリューションに気にしません。

答えて

5

ON DUPLICATE KEY UPDATE代替は、データベースに挿入決断対アップデートを参照することができます:ユーザーID 2を持つエントリがすでに存在する場合

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

は、「ボビー」に名前フィールドを更新します。

更新するnoneffective操作を供給する場合は、INSERT IGNOREの代替として使用することができます:ユーザーID 2がすでに存在する場合

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

は、これは何もしないだろう、これ他のエラーの警告や嚥下を回避INSERT IGNOREを使用したときに表示されます。


別の方法としては、REPLACE次のようになります。

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

ユーザーID 2がまだ存在しない場合、これは通常の挿入を行うだろう。存在する場合は、古いエントリを最初に削除し、新しいエントリを挿入します。


どちらのバージョンもSQL固有のMySQL拡張です。 Zend Frameworkのために

0

ループでは、最初に更新を行うことができます。影響を受ける行がない場合は、新しいエントリです。これらの「失敗した更新」を追跡し、新しいエントリとして挿入します。

私はZend_Dbに慣れていませんが、更新が行の数に影響を与えるかどうかを返すことができます。ユーザーID 2が既にそれは無視して次の挿入に移りますが存在する場合

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

+0

どういうわけか、私は読み違えます既存のユーザーが見つかった場合は更新する必要があるかどうかを質問し、そうでない場合は新しいものとして挿入します。 well ... down-voted –

2

あなたがPRIMARYまたはUNIQUEキーとしてユーザーIDを定義し、のようなものを使用する必要があります。

テーブルスキーマでON DUPLICATE KEY UPDATEを使用することもできます。 もう1つの方法は、REPLACE INTO構文を使用することです。

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

レコードがすでにそれが再びそれを挿入する前に、それを削除しますが存在する場合、これは、挿入しようとします。

+0

Zend_Dbでは 'INSERT IGNORE'がサポートされていますか? –

+0

正直、NoFId。 –

+0

'IGNORE'は、dbエンジンにエラーの代わりに警告を発行させるので、クエリの実行は停止しません。このアプローチの欠点は、重大なキーだけでなく、発生したエラーが無視され警告に変わることです。 –

4

、私は何をするINSERT文ののtry/catchで例外コードに基づいてさらなる行動を取る:

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

Strict Standardsのために$ bIgnoreをあきらめる必要があります:Your_Model :: insert()の宣言はZend_Db_Table_Abstract :: insert(array $ data)と互換性があります。 – bensiu

1

私のソリューション:

/** 
* 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(); 
} 
関連する問題