_on_conditionを挿入または置換したいと思います。条件が満たされない場合は、挿入または交換しないでください。これは可能ですか?
私のプロジェクトでは、現在2つのデータ収集プロセスがあります。 1つは高速ですが、すべてをキャッチするわけではありません。もう1つは遅いですが、すべてをキャッチします。高速プロセスにより、ほぼリアルタイムでデータを取得できます。遅いものでは、一日の終わりにバッチプロセスを使用してデータを取得します。
私の問題はこれです:時々、速いプロセスは遅いプロセスの前にレコードを「完了する」(つまり、更新する必要がない)、そして夜のバッチプロセスの後半に、「完了」レコードはに置き換えられます遅いプロセスのバルクデータで見つかった古い「保留中」のレコード。
私が欲しいのは、次の擬似コードのような条件チェックです。
If(record_is_not_complete or does_not_exist)
{ INSERT or REPLACE; }
Else
{ do_nothing and move_to_the_next; }
標準のINSERT OR REPLACE
の例から始める場合:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'COMPLETE', 5);
これにより、UserProgressテーブルにエントリ[1、COMPLETE、5]の行が表示されます。
次の場合:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'PENDING', 4);
すでにCOMPLETEレコードがあるので、これをスキップしたいと思います。
これは重複した質問だと確信しています。しかし、それは本当にですか?この質問に対する答えはたくさんありますが、どれが最善のアプローチかわかりません。私が見つけたこれらすべての例を見てください:
CASE
ステートメントを追加しようと試みることができます。IF-THEN-ELSE
ステートメントと同等であると言われています。 この例で行われているように。
SELECT
でCOALESCE
またはVALUES
ステートメントを使用してみることができます。 この例で行われているように。
SELECT WHERE
ステートメントを使用することもできます。 この例で行われているように。
LEFT JOIN
ステートメントの使用を試みることができます。 この例で行われているように。
これはSQLiteに最適です。同じ猫の皮を剥ぐ方法は複数あるようです。私は初心者なので、今は混乱しています。どのアプローチを使用すべきかは明確ではありません。
1つのSQLステートメントで実行できるソリューションを探しています。
*更新*
2つのトランザクションソリューションを見つけました。私はまだ単一のトランザクションソリューションを探しています。
これは機能しますが、2つのトランザクションを使用します。
public void Create(IEnumerable<UserProgress> items)
{
var sbFields = new StringBuilder();
sbFields.Append("ID,");
sbFields.Append("STATUS,");
sbFields.Append("LEVEL,");
int numAppended = 3;
var sbParams = new StringBuilder();
for (int i = 1; i <= numAppended; i++)
{
sbParams.Append("@param");
sbParams.Append(i);
if (i < numAppended)
{
sbParams.Append(", ");
}
}
// attempting this solution: https://stackoverflow.com/questions/2251699/sqlite-insert-or-replace-into-vs-update-where
// first insert the new stuff.
using (var command = new SQLiteCommand(Db))
{
command.CommandText = "INSERT OR IGNORE INTO USERPROGRESS (" + sbFields + ") VALUES(" + sbParams + ")";
command.CommandType = CommandType.Text;
using (var transaction = Db.BeginTransaction())
{
foreach (var user in items)
{
command.Parameters.Add(new SQLiteParameter("@param1", user.Id));
command.Parameters.Add(new SQLiteParameter("@param2", user.Status));
command.Parameters.Add(new SQLiteParameter("@param3", user.Level));
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
using (var command = new SQLiteCommand(Db))
{
string parameterized = "";
for (int i = 1; i <= 3; i++)
{
parameterized += _columnNames[i - 1] + "=" + "@param" + i;
if (i != 3)
parameterized += ",";
}
command.CommandText = "UPDATE USERPROGRESS SET " + parameterized + " WHERE ID=@param1 AND STATUS !='COMPLETE'";
command.CommandType = CommandType.Text;
using (var transaction = Db.BeginTransaction())
{
foreach (var user in items)
{
command.Parameters.Add(new SQLiteParameter("@param1", user.Id));
command.Parameters.Add(new SQLiteParameter("@param2", user.Status));
command.Parameters.Add(new SQLiteParameter("@param3", user.Level));
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
}
[〜#〜] sql [〜#〜]
INSERT OR REPLACE INTO UserProgress (id, status, level) SELECT
id value, '
ステータス値',
レベル値WHERE NOT EXISTS (SELECT * FROM UserProgress WHERE id =
id valueAND status = 'COMPLETE');
(ここでid value、ステータス値およびレベル値必要に応じて挿入されます)
デモ
http://www.sqlfiddle.com/#!5/a9b82d/1
説明
EXISTS
部分は、ステータス値が'COMPLETE'
である同じid
を持つ既存の行がテーブルにあるかどうかを確認するために使用されます。この条件が一致した場合、何も実行されません(WHERE NOT
のため)。それ以外の場合、指定されたid
の行は、存在しない場合はINSERTされるか、存在する場合は指定された値で更新されます(INSERT OR REPLACE
のため)。
IFステートメントには、IF-THEN、IF-THEN-ELSE、およびIF-THEN-ELSIFの3つの形式があります。
SQLiteでIfステートメントを使用する構文は次のとおりです。
IF expr THEN statement-list
[ELSIF expr THEN statement-list ]*
[ELSE statement-list]
END IF