Предсказать следующий автоматически вставленный идентификатор строки (SQLite)
Я пытаюсь найти, если есть надежный способ (используя SQLite), чтобы найти идентификатор следующей строки вставлен, прежде чем он встанет. Мне нужно использовать id для другого оператора insert, но у вас нет возможности мгновенно вставлять и получать следующую строку.
Предсказывает следующий id так же просто, как получить последний идентификатор и добавить его? Это гарантия?
Изменить: немного больше рассуждений...
Я не могу вставить сразу, потому что вставка может быть отменена пользователем. Пользователь внесет некоторые изменения, операторы SQL будут сохранены, и оттуда пользователь может либо сохранить (вставить все строки сразу), либо отменить (не меняя ничего). В случае сбоя программы желаемая функциональность заключается в том, что ничего не изменилось.
Ответы
Ответ 1
Либо ломать, либо совершать ряд операций с базой данных одновременно - это именно то, для чего нужны транзакции. Запросить BEGIN;
, прежде чем пользователь начнет возиться и COMMIT;
после его выполнения. Вам гарантировано, что либо все изменения будут применены (если вы зафиксируете), либо все будет отменено (если вы запросите ROLLBACK;
, если программа выйдет из строя, питание отключится и т.д.). После того, как вы прочитали из db, вы также гарантируете, что данные будут хорошими до конца транзакции, поэтому вы можете захватить MAX(id)
или все, что хотите, не беспокоясь о состоянии гонки.
http://www.sqlite.org/lang_transaction.html
Ответ 2
Попробуйте SELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';
. Это будет содержать поле под названием seq
, которое является наибольшим числом для выбранной таблицы. Добавьте 1 к этому значению, чтобы получить следующий идентификатор.
Также см. статью SQLite Autoincrement, в которой появилась вышеприведенная информация.
Ура!
Ответ 3
Вы можете уйти с добавлением 1 к значению, возвращенному sqlite3_last_insert_rowid при определенных условиях, например, с использованием того же соединения с базой данных и других авторов не существует. Конечно, вы можете ссылаться на исходный код sqlite для резервного копирования этих допущений.
Однако вы также можете серьезно подумать об использовании другого подхода, который не требует прогнозирования следующего идентификатора. Даже если вы правильно это понимаете для используемой версии sqlite, все может измениться в будущем, и это, безусловно, затруднит переход к другой базе данных.
Ответ 4
Вставьте строку с каким-либо флагом INVALID, получите идентификатор, отредактируйте его, если необходимо, удалите, если необходимо, или отметьте как действительный. Это и не беспокойтесь о пробелах в последовательности
Кстати, вам нужно будет выяснить, как сделать недействительную часть самостоятельно. Маркировка чего-то, поскольку NULL может работать в зависимости от специфики.
Изменить: если вы можете, используйте предложение Eevee об использовании правильных транзакций. Это намного меньше работает.
Ответ 5
Я понимаю, что ваше приложение с использованием SQLite мало, а SQLite имеет свою собственную семантику. Другие решения, размещенные здесь, вполне могут иметь эффект, который вы хотите в этой конкретной настройке, но, на мой взгляд, каждый из них, который я прочитал до сих пор, принципиально неверен и его следует избегать.
В нормальном окружении следует избегать транзакции для ввода пользователем любой ценой. Способ справиться с этим, если вам нужно хранить промежуточные данные, заключается в том, чтобы записать эту информацию в таблицу с нуля для этой цели, а затем попытаться написать всю информацию в атомной транзакции. Операции с холдингом предполагают взаимоблокировки и кошмары concurrency в многопользовательской среде.
В большинстве сред вы не можете предположить, что данные, полученные с помощью SELECT в транзакции, повторяются. Например
SELECT Balance FROM Bank ...
UPDATE Bank SET Balance = valuefromselect + 1.00 WHERE ...
После UPDATE значение баланса может быть изменено. Иногда вы можете обойти это, обновив строку (ы), которую вы заинтересованы в Банке, сначала в рамках транзакции, так как это гарантирует блокировку строки, которая препятствует дальнейшим обновлениям изменять значение до завершения транзакции.
Однако иногда лучший способ обеспечить согласованность в этом случае - проверить ваши предположения о содержимом данных в предложении WHERE обновления и проверить количество строк в приложении. В приведенном выше примере, когда вы "UPDATE Bank", предложение WHERE должно предоставить ожидаемое текущее значение баланса:
WHERE Balance = valuefromselect
Если ожидаемый баланс больше не соответствует ни условию WHERE - UPDATE ничего не делает, а rowcount возвращает 0. Это говорит о том, что существует проблема с concurrency, и вам нужно снова запустить операцию, когда что-то еще не пытается для изменения ваших данных одновременно.
Ответ 6
select max(id) from particular_table is unreliable for the reason below..
http://www.sqlite.org/autoinc.html
"Обычный алгоритм выбора ROWID, описанный выше, будет генерировать монотонно увеличивающиеся уникальные ROWID, если вы никогда не используете максимальное значение ROWID, и никогда не удаляете запись в таблице с наибольшим ROWID. Если вы когда-либо удаляете строки или когда-либо создать строку с максимально возможным ROWID, тогда ROWID из ранее удаленных строк могут быть повторно использованы при создании новых строк, а вновь созданные ROWID могут быть не в строго возрастающем порядке."
Ответ 7
Я думаю, что это невозможно сделать, потому что нет никакого способа убедиться, что между запросом и вставкой ничего не встанет. (вы можете заблокировать таблицу для вставки, но Yuck)
BTW Я только использовал MySQL, но я не думаю, что это будет иметь значение)
Ответ 8
Скорее всего, вы должны обладать +1 самым последним идентификатором. Я бы посмотрел на все (время назад) на существующий идентификатор в упорядоченной таблице. Являются ли они согласованными и каждый идентификатор строки один больше последнего? Если это так, вы, вероятно, будете в порядке. Однако я оставляю комментарии в коде, объясняющем предположение. Выполнение блокировки поможет гарантировать, что вы не получите дополнительные строки, пока вы это делаете.
Ответ 9
Выберите значение last_insert_rowid().
Ответ 10
Больше всего, что нужно сказать в этой теме, уже есть... Однако, будьте очень осторожны в условиях гонки при этом. Если два человека открывают ваше приложение/веб-страницу/независимо, а один из них добавляет строку, другой пользователь попытается вставить строку с тем же идентификатором, и у вас будет много проблем.
Ответ 11
select max(id) from particular_table;
Следующий идентификатор будет равен +1 от максимального id.