Предсказать следующий автоматически вставляемый идентификатор строки (SQLite)

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

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

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

У меня есть интересная куча кода, который делает что-то более простое и использует int col "транзакции", который имеет значение null для реальных данных и некоторое значение для ожидающих изменений. Все правки пользователя имеют одинаковую ценность

BCS 20.09.2008 08:15

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

foobar 20.09.2008 08:19

Так есть ли ответ, как получить последний идентификатор автоинкремента?

Solid I 06.04.2012 04:23
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
17
3
18 279
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

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

Кстати, я использовал только MySQL, но не думаю, что это будет иметь значение)

На самом деле я могу быть уверен, что ничего не вставляется, поскольку это простая клиентская программа.

foobar 20.09.2008 07:55

Вы не можете быть уверены, если не являетесь единственным пользователем.

BCS 20.09.2008 08:00

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

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

Кстати, пока вы выполняете выбор в рамках того же подключения к базе данных, вы получите идентификатор вставленной вами записи. Никакой «блокировки» не требуется.

Jason Stevenson 20.09.2008 07:53

Уточнение, извините, я не внимательно прочитал ваш вопрос. Пытаться предсказать следующий идентификатор - плохая идея. Было бы намного лучше, вставив строку, получив идентификатор. Затем выполните другую работу с sql и затем вернитесь, чтобы обновить эту запись.

Jason Stevenson 20.09.2008 07:55

Джейсон Стивенсон: Причина, по которой я не могу этого сделать, в том, что мне, возможно, придется отменить редактирование. Я сохраняю инструкцию вставки на потом.

foobar 20.09.2008 07:57

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

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

Спасибо. эта команда была именно тем, что я искал, из-за возникшей у меня проблемы. знак равно

Ben 04.11.2014 09:07

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

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

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

Хорошо, перечитывая, думаю, я понимаю, что вы имеете в виду, то же самое, что и в вашем комментарии. Я думал, вы говорите о функции sqlite. Ну что ж...

foobar 20.09.2008 08:21

Точка зрения Иви хороша, но не всегда осуществима. Если правки должны охватывать сеансы, или механизм хранения не поддерживает переводы, ваш запрос потерпел неудачу.

BCS 20.09.2008 08:54
Ответ принят как подходящий

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

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

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

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

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

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

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

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

Однако иногда лучший способ обеспечить согласованность в этом случае - это проверить ваши предположения о содержимом данных в предложении WHERE обновления и проверить количество строк в приложении. В приведенном выше примере, когда вы "UPDATE Bank", предложение WHERE должно предоставить ожидаемое текущее значение баланса:

WHERE Balance = valuefromselect

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

select max(id) from particular_table;

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

Проголосовали против, потому что это не работает, как только вы удаляете последнюю вставленную строку: при удалении последней строки, скажем, с идентификатором 15, MAX (id) вернет 14 или ниже, но следующий вставленный идентификатор будет 16 из-за таблицы SQLITE_SEQUENCE запоминание последнего вставленного идентификатора.

Thomas Tempelmann 04.12.2014 13:35

@ThomasTempelmann другие возможности рассинхронизации включают операторы INSERT OR IGNORE, ограничения внешнего ключа и транзакции отката.

Gaspa79 14.08.2020 21:16

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

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

Ваше здоровье!

SELECT seq FROM SQLITE_SEQUENCE WHERE name = 'TABLE' LIMIT 1;

ban-geoengineering 04.08.2017 16:51

Это кажется неправильным, поскольку вы предполагаете, что 1) таблица имеет AUTOINCREMENT, 2) следующий идентификатор будет точно следующим промежуточным числом, которое гарантировано нет, только то, что оно будет больше, чем это.

grin 27.11.2018 14:37

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

Другие вопросы по теме