I would like to insert or replace_on_condition. If the condition is not satisfied, do not insert or replace. Is this possible?
For my project, I currently have two data collection processes. One is fast but doesn't catch everything. The other is slow but catches everything. With the fast process, I get data almost in real time. With the slow one I get data using a batch process at the end of day.
My issue is this: sometimes the fast process will "Complete" a record (meaning it no longer needs to be updated) BEFORE the slow process, and later in the day during the nightly batch process, the "Complete" record will get replaced by an outdated "Pending" record found in the slow process's bulk data.
What I would like is a conditional check that goes something like this pseudocode:
If(record_is_not_complete or does_not_exist)
{ INSERT or REPLACE; }
Else
{ do_nothing and move_to_the_next; }
If I begin with a standard INSERT OR REPLACE
example:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'COMPLETE', 5);
Which should result in a row in UserProgress table with entry [1,COMPLETE,5].
If the following occurs:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'PENDING', 4);
I would like for it to skip this, because there is already a COMPLETE record.
I'm sure this is a duplicate question. But is it really? There are so many answers to this question I am not sure which is the best approach. Look at all these examples that I found:
I can attempt to add a CASE
statement, I have been told it is equivalent to a IF-THEN-ELSE
statement. As done in this example.
I can attempt to use SELECT
or COALESCE
statement in the VALUES
. As done in this example.
I can even attempt to use a SELECT WHERE
statement. As done in this example.
I can attempt to use an LEFT JOIN
statement. As done in this example.
Which is great for SQLite. There appears to be multiple ways to skin the same cat. Me being a novice I am now confused. It isn't clear which approach I should be using.
I am looking for a solution that can be done in one sql statement.
* UPDATE *
I found a two transaction solution. I'm still on the hunt for a single transaction solution.
This works, but uses two transactions:
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();
}
}
}
insert or ignore ... will insert the row(s) and ignore rows which violation any constraint (other than foreign key constraints).
To insert data into a table, you use the INSERT statement. SQLite provides various forms of the INSERT statements that allow you to insert a single row, multiple rows, and default values into a table. In addition, you can insert a row into a table using data provided by a SELECT statement.
You can use the INSERT OR REPLACE statement to write new rows or replace existing rows in the table. The syntax and behavior of the INSERT OR REPLACE statement is similar to the INSERT statement. Unlike the INSERT statement, the INSERT OR REPLACE statement does not generate an error if a row already exists.
SQL
INSERT OR REPLACE INTO UserProgress (id, status, level) SELECT '
id value', '
status value', '
level value'
WHERE NOT EXISTS (SELECT * FROM UserProgress WHERE id = '
id value' AND status = 'COMPLETE');
(where id value, status value and level value are inserted as appropriate)
Demo
http://www.sqlfiddle.com/#!5/a9b82d/1
Explanation
The EXISTS
part is used to find out whether there is an existing row in the table with the same id
whose status value is 'COMPLETE'
. If this condition is matched, nothing is done (due to the WHERE NOT
). Otherwise, the row with the specified id
is either INSERTed if not present or UPDATEd with the specified values if present (due to the INSERT OR REPLACE
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With