Как условно вставить или заменить строку в SQLite?

я хотел бы вставить или replace_on_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);

я хотел бы пропустить это, потому что уже есть полная запись.

я уверен, что это дубликат вопрос. Но так ли это на самом деле? Есть так много ответов на этот вопрос я не уверен, что это лучший подход. Посмотрите на все эти примеры, которые я нашел:

я могу попытаться добавить CASE заявление, мне сказали, что это эквивалентно а IF-THEN-ELSE заявление. как сделано в этом примере.

я могу попытаться использовать SELECT или COALESCE заявление в VALUES. как сделано в этом примере.

я даже могу попытаться использовать SELECT WHERE заявление. как сделано в этом примере.

я могу попытаться использовать LEFT JOIN заявление. как сделано в этом примере.

что отлично подходит для SQLite. Существует несколько способов шкура той же кошки. Будучи новичком, я сейчас в замешательстве. Не ясно, какой подход я должен использовать.

я ищу решение, которое можно сделать в одной инструкции sql.

* UPDATE*

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

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

 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();
                }
            }
        }

2 ответов


среда SQL

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

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

демо

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

объяснение

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


существует три формы операторов 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