Прогнозировать следующий автоматически вставленный идентификатор строки (SQLite) - PullRequest
15 голосов
/ 20 сентября 2008

Я пытаюсь найти надежный способ (используя SQLite ) найти идентификатор следующей строки, которую нужно вставить, до того, как она будет вставлена ​​. Мне нужно использовать идентификатор для другого оператора вставки, но у меня нет возможности мгновенно вставить и получить следующую строку.

Предсказать следующий идентификатор так же просто, как получить последний идентификатор и добавить его? Это гарантия?

Редактировать: немного больше рассуждений ... Я не могу вставить сразу, потому что пользователь может отменить вставку. Пользователь внесет некоторые изменения, операторы SQL будут сохранены, и оттуда пользователь может либо сохранить (вставив все строки сразу), либо отменить (ничего не меняя). В случае сбоя программы желаемая функциональность заключается в том, что ничего не меняется.

Ответы [ 11 ]

23 голосов
/ 14 марта 2011

Попробуйте SELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';. Это будет содержать поле с именем seq, которое является наибольшим числом для выбранной таблицы. Добавьте 1 к этому значению, чтобы получить следующий идентификатор.

Также см. статью об автоинкременте SQLite , из которой вышла вышеуказанная информация.

ура!

14 голосов
/ 20 сентября 2008

Либо удаление, либо совершение сразу нескольких операций с базой данных - это как раз то, для чего нужны транзакции. Запросите BEGIN;, прежде чем пользователь начнет возиться, и COMMIT;, как только он / она закончит. Вам гарантировано, что либо все изменения будут применены (если вы делаете коммит), либо все будет отменено (если вы запросите ROLLBACK;, если программа выйдет из строя, отключится питание и т.д.) Когда вы читаете из базы данных, вы также гарантируете, что данные в порядке до конца транзакции, поэтому вы можете получить MAX(id) или что угодно, не беспокоясь о состоянии гонки.

http://www.sqlite.org/lang_transaction.html

3 голосов
/ 20 сентября 2008

Возможно, вам не удастся добавить 1 к значению, возвращаемому sqlite3_last_insert_rowid при определенных условиях, например, при использовании того же соединения с базой данных и других параллельных писателей нет. Конечно, вы можете обратиться к исходному коду sqlite для подтверждения этих предположений.

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

2 голосов
/ 23 ноября 2011
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 могут быть не в строго возрастающем порядке. "

2 голосов
/ 04 января 2009

Я понимаю, что ваше приложение, использующее SQLite, невелико, и SQLite имеет свою семантику. Другие решения, опубликованные здесь, вполне могут иметь тот эффект, который вам нужен в этом конкретном случае, но, на мой взгляд, каждое из них, которое я читал до сих пор, в корне неверно и его следует избегать.

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

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

SELECT Balance FROM Bank ...
UPDATE Bank SET Balance = valuefromselect + 1.00 WHERE ...

После ОБНОВЛЕНИЯ значение баланса вполне может быть изменено. Иногда вы можете обойти это, обновив строку (-ы), интересующую вас Банком, сначала в рамках транзакции, так как это гарантированно блокирует строку, предотвращая дальнейшее изменение значения, пока ваша транзакция не будет завершена.

Однако иногда лучшим способом обеспечения согласованности в этом случае является проверка ваших предположений о содержании данных в предложении WHERE обновления и проверка количества строк в приложении. В приведенном выше примере, когда вы «ОБНОВЛЯЕТЕ Банк», предложение WHERE должно указывать ожидаемое текущее значение баланса:

WHERE Balance = valuefromselect

Если ожидаемый баланс больше не совпадает, то и условие WHERE не выполняется - UPDATE ничего не делает, а rowcount возвращает 0. Это говорит о том, что возникла проблема с параллелизмом, и вам нужно снова запустить операцию, когда что-то другое не пытается изменить ваши данные одновременно.

2 голосов
/ 20 сентября 2008

Вставьте строку с каким-либо флагом INVALID, получите идентификатор, отредактируйте его, если необходимо, удалите, если необходимо, или отметьте как действительный. Это и не беспокойтесь о пробелах в последовательности

Кстати, вам нужно выяснить, как сделать недействительную часть самостоятельно. Пометка чего-либо как NULL может работать в зависимости от специфики.

Редактировать: Если можете, воспользуйтесь предложением Евы об использовании правильных транзакций. Это намного меньше работы.

0 голосов
/ 08 марта 2011
select max(id) from particular_table;

Следующий идентификатор будет +1 от максимального идентификатора.

0 голосов
/ 20 сентября 2008

Большая часть всего, что нужно сказать в этой теме, уже имеет ... Однако при этом будьте очень внимательны к условиям гонки . Если два человека одновременно откроют ваше приложение / веб-страницу / что угодно, и один из них добавит строку, другой пользователь попытается вставить строку с тем же идентификатором, и у вас возникнет множество проблем.

0 голосов
/ 20 сентября 2008

Выберите значение last_insert_rowid ().

0 голосов
/ 20 сентября 2008

Скорее всего, вы сможете +1 самый последний идентификатор. Я бы посмотрел на все (возвращаясь на некоторое время) существующих идентификаторов в упорядоченной таблице. Являются ли они последовательными, и является ли идентификатор каждой строки на единицу больше, чем последний? Если это так, вы, вероятно, будете в порядке. Однако я оставил бы комментарии в коде, объясняющие это предположение. Выполнение блокировки поможет гарантировать, что вы не получите дополнительных строк, пока вы это делаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...