Если select возвращает 0 строк, вставьте данные

#ios #database #html #web-sql

#iOS #База данных #HTML #web-sql

Вопрос:

В настоящее время у меня есть транзакция, которая пытается вставить данные в таблицу. Если данные уже есть в таблице, возникает ошибка с ошибкой ограничения, и выполняется выбор для получения идентификатора.

 t2.executeSql('INSERT INTO books (book) VALUES (?);',
  [record],
  function (t2, r) {        // SQL_successfulCallback
    record = r.insertId;
  },
  function (t2, err) {      // SQL_errorCallback
    if (err.message !== 'constraint failed') { // insert failed because of other
                                               // reason - fail transaction
      console.log('Insert SQL error '   err.code   ' - '   err.message   '.');
      return true;
    } else { // insert failed because data was already in the table
      t2.executeSql('SELECT bookID FROM books WHERE book=?',
        [record],
        function (t, r) {   // SQL_successfulCallback
          record = r.rows.item(0).classificationID;
        },
        function (t, err) { // SQL_errorCallback
          console.log('Lookup SQL error '   err.code   ' - '   err.message   '.');
          return true;
        }
      );
      return false;
    }
  }
);
 

Я хочу ускорить транзакцию, поэтому подумал, что сначала посмотрю, были ли данные в таблице. Если это не так, вставьте его…

 t2.executeSql('SELECT bookID FROM books WHERE book=?',
  [record],
  function (t2, r) {          // SQL_successfulCallback
    if (r.rows.length !== 0) {
      record = r.rows.item(0).bookID;
    } else {
      t2.executeSql('INSERT INTO books (book) VALUES (?);',
        [record],
        function(t2, r){      // SQL_successfulCallbac
          record = r.insertId;
        },
        function (t2, err) {  // SQL_errorCallback
          if (err.message !== 'constraint failed') { // insert failed because of other
                                                     // reason - fail transaction
            console.log('Insert SQL error '   err.code   ' - '   err.message   '.');
            return true;
          } else { // insert failed because data was already in the table
            return false;
          }
        }
      );
    }
  },
  function (t, err) {         // SQL_errorCallback
    console.log('Lookup SQL error '   err.code   ' - '   err.message   '.');
    return true;
  }
);
 

… но это не работает. Эта транзакция запускает все выборки, а затем выполняет вставки. Как я могу заставить второй метод работать?

Ответ №1:

Я предполагаю, что транзакция ставит запрос в очередь. Таким образом, ваша очередь будет выглядеть следующим образом

Выберите 1

Выберите 2

Выберите 3

Затем, когда вы фиксируете, ваша транзакция выглядит так после первого вызова.

Выберите 2

Выберите 3

Вставка 1

Вставьте 2

Вставьте 3

Это происходит потому, что функции для вызова вставок выполняются после запуска select, и этого не происходит до тех пор, пока транзакция не будет зафиксирована, но выбранные элементы уже зарегистрированы.

Для того, чтобы заставить его быть

выберите 1

insert1

выберите 2

insert2

Я бы создал отдельную транзакцию для каждого оператора select.

Комментарии:

1. НЕ ВЫПОЛНЯЙТЕ МЕТОД 2! Метод 1 занимает 22 секунды с 28 439 записями. Метод 2 с оболочкой транзакции, предложенный Майклом, занимает 34 секунды для того же количества записей!

2. Как вы можете сразу вставлять записи и как вы получаете данные для ввода. Я предполагал, что пользователи просто вводят пару записей за раз, так ли это, или вы вставляете 28 439 записей одновременно?

3. Данные поступают из файлов JSON. Вместо того, чтобы искать, а затем вставлять, я создаю массивы в памяти для хранения уникальных значений для таблиц, а затем использую этот меньший массив для выполнения вставок.