86

次のカウンターの表があります。

CREATE TABLE cache (
    key text PRIMARY KEY,
    generation int
);

カウンターの1つをインクリメントするか、対応する行がまだ存在しない場合はゼロに設定したいと思います。標準SQLで並行性の問題なしにこれを行う方法はありますか?操作はトランザクションの一部である場合もあれば、別個の場合もあります。

SQLは、可能であれば、SQLite、PostgreSQL、およびMySQLで変更せずに実行する必要があります。

検索により、並行性の問題に悩まされているか、データベースに固有のいくつかのアイデアが得られました。

  • INSERT新しい行を試してUPDATE、エラーが発生した場合。残念ながら、のエラーINSERTは現在のトランザクションを中止します。

  • UPDATE行、および行が変更されていない場合はINSERT、新しい行。

  • MySQLにはON DUPLICATE KEY UPDATE句があります。

編集:すべての素晴らしい返信をありがとう。ポールは正しいように見えますが、これを行うための単一のポータブルな方法はありません。非常に基本的な操作のように聞こえるので、それは私にとって非常に驚くべきことです。

4

10 に答える 10

143

MySQL(およびその後のSQLite)もREPLACEINTO構文をサポートしています。

REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');

これにより、主キーが自動的に識別され、更新する一致する行が検索されます。見つからない場合は、新しい行が挿入されます。

ドキュメント:https ://dev.mysql.com/doc/refman/8.0/en/replace.html

于 2009-03-27T17:15:03.427 に答える
33

行が既に存在する場合、 SQLiteは行の置換をサポートします。

INSERT OR REPLACE INTO [...blah...]

これを短くすることができます

REPLACE INTO [...blah...]

REPLACE INTOこのショートカットは、MySQL式と互換性を持たせるために追加されました。

于 2009-03-27T17:19:10.577 に答える
28

私は次のようなことをします:

INSERT INTO cache VALUES (key, generation)
ON DUPLICATE KEY UPDATE (key = key, generation = generation + 1);

コードまたはSQLで生成値を0に設定しますが、ON DUP ...を使用して値を増やします。とにかくそれが構文だと思います。

于 2009-03-27T17:45:40.997 に答える
9

ON DUPLICATE KEY UPDATE 句が最適なソリューションです。その理由は、REPLACE は DELETE の後に INSERT を実行するため、ごくわずかな期間レコードが削除されるため、ページがREPLACE クエリ中に表示されます。

そのため、INSERT ... ON DUPLICATE UPDATE ... を好みます。

jmoz のソリューションが最適です。ただし、かっこよりも SET 構文の方が好きです

INSERT INTO cache 
SET key = 'key', generation = 'generation'
ON DUPLICATE KEY 
UPDATE key = 'key', generation = (generation + 1)
;
于 2009-03-28T22:47:50.280 に答える
8

プラットフォームに中立なソリューションを見つけるつもりかどうかはわかりません。

これは一般に「UPSERT」と呼ばれます。

関連するいくつかの議論を参照してください。

于 2009-03-27T17:10:43.127 に答える
4

標準 SQL は、このタスクのための MERGE ステートメントを提供します。すべての DBMS が MERGE ステートメントをサポートしているわけではありません。

于 2009-03-27T17:27:11.650 に答える
0

アトミックに更新または挿入する一般的な方法がない場合(たとえば、トランザクションを介して)、別のロックスキームにフォールバックできます。0バイトのファイル、システムミューテックス、名前付きパイプなど。

于 2009-03-27T17:11:07.680 に答える
0

挿入トリガーを使用できますか?失敗した場合は、更新を行ってください。

于 2009-03-27T17:12:25.557 に答える