Как условно ВСТАВИТЬ ИЛИ ЗАМЕНИТЬ строку в SQLite?

Я хотел бы вставить или заменить_con_condition. Если условие не выполняется, не вставляйте и не заменяйте. Это возможно?

В моем проекте у меня в настоящее время есть два процесса сбора данных. Один быстро, но не все. Другой медленный, но ловит все. С быстрым процессом я получаю данные почти в режиме реального времени. С медленным я получаю данные, используя пакетный процесс в конце дня.

Моя проблема заключается в следующем: иногда быстрый процесс будет "завершать" запись (это значит, что ее больше не нужно обновлять) ПЕРЕД медленным процессом, а позже в течение дня в ночном режиме партии, "полная" запись будет замените на устаревшую "ожидающую" запись, обнаруженную в данных объемного процесса медленного процесса.

Я бы хотел, чтобы это была условная проверка, которая похожа на этот псевдокод:

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. Кажется, существует несколько способов обмануть одного и того же кота. Я, будучи новичком, теперь запутался. Неясно, какой подход я должен использовать.

Я ищу решение, которое можно выполнить в одном заявлении sql.

* ОБНОВЛЕНИЕ *

Я нашел два решения для транзакций. Я все еще нахожусь в поиске единственного решения для транзакций.

Это работает, но использует две транзакции:

 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/info/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 [email protected] 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();
                }
            }
        }

Ответ 1

SQL

INSERT OR REPLACE INTO UserProgress (id, status, level) SELECT значение id , ' значение статуса ', значение уровня WHERE NOT EXISTS (SELECT * FROM UserProgress WHERE id = значение id AND status = 'COMPLETE');

(где значение id, значение статуса и значение уровня вставлены соответственно)

Demo

http://www.sqlfiddle.com/#!5/a9b82d/1

Объяснение

Часть EXISTS используется, чтобы узнать, существует ли существующая строка в таблице с тем же id, значение статуса которой 'COMPLETE'. Если это условие согласовано, ничего не делается (из-за WHERE NOT). В противном случае строка с указанным id будет либо INSERTed, если не присутствует, либо UPDATEd с указанными значениями, если они присутствуют (из-за INSERT OR REPLACE).

Ответ 2

Существуют три формы операторов IF: IF-THEN, IF-THEN-ELSE и IF-THEN-ELSIF.

Синтаксис использования оператора If в SQLite:

IF expr THEN statement-list
[ELSIF expr THEN statement-list ]*
[ELSE statement-list]
END IF

Связано: https://www.sqliteconcepts.org/pl_if.html