Q&Aスタイル
まあ、何時間も問題を調査して戦った後、テーブルの構造と、整合性を維持するためにアクティブ化された外部キー制限があるかどうかによって、これを達成する方法が2つあることがわかりました。私の状況にいる可能性のある人々に時間を節約するために、これをきれいな形式で共有したいと思います。
オプション1:行を削除する余裕がある
つまり、外部キーがないか、外部キーがある場合は、整合性の例外がないようにSQLiteエンジンが構成されています。行く方法はINSERT OR REPLACEです。IDが既に存在するプレーヤーを挿入/更新しようとすると、SQLiteエンジンはその行を削除し、提供しているデータを挿入します。今問題が来ます:古いIDを関連付けておくために何をすべきか?
データuser_name = ' steven 'およびage = 32でUPSERTを実行するとします。
このコードを見てください:
INSERT INTO players (id, name, age)
VALUES (
coalesce((select id from players where user_name='steven'),
(select max(id) from drawings) + 1),
32)
トリックは合体です。存在する場合はユーザー「steven」のIDを返し、それ以外の場合は新しい新しいIDを返します。
オプション2:行を削除する余裕がない
前の解決策を試してみたところ、このIDは他のテーブルの外部キーとして機能するため、データが破壊される可能性があることに気付きました。さらに、ON DELETE CASCADE句を使用してテーブルを作成しました。これは、データをサイレントに削除することを意味します。危険な。
したがって、最初にIF句について考えましたが、SQLiteにはCASEしかありません。そして、このCASEを使用して(または少なくとも管理しなかった)、EXISTS(select id from player where user_name = 'steven')の場合は1つのUPDATEクエリを実行できず、そうでない場合はINSERTを実行できません。立ち入り禁止。
そして、ついに私はブルートフォースを使用し、成功しました。ロジックは、実行するUPSERTごとに、まずINSERT OR IGNOREを実行してユーザーの行があることを確認してから、挿入しようとしたまったく同じデータを使用してUPDATEクエリを実行します。
以前と同じデータ:user_name = 'steven'およびage = 32。
-- make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);
-- make sure it has the right data
UPDATE players SET user_name='steven', age=32 WHERE user_name='steven';
そしてそれだけです!
編集
Andyがコメントしているように、最初に挿入してから更新しようとすると、トリガーが頻繁にトリガーされる可能性があります。これは私の意見ではデータの安全性の問題ではありませんが、不要なイベントを発生させることはほとんど意味がないことは事実です。したがって、改善されたソリューションは次のとおりです。
-- Try to update any existing row
UPDATE players SET age=32 WHERE user_name='steven';
-- Make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);