Predecir la siguiente identificación de fila insertada automáticamente (SQLite)

StackOverflow https://stackoverflow.com/questions/107005

  •  01-07-2019
  •  | 
  •  

Pregunta

Estoy tratando de encontrar si hay una manera confiable (usando SQLite) para encontrar el ID de la siguiente fila a insertar, antes de que se inserte.Necesito usar la identificación para otra declaración de inserción, pero no tengo la opción de insertar y obtener instantáneamente la siguiente fila.

¿Predecir la siguiente identificación es tan simple como obtener la última identificación y agregar una?¿Es eso una garantía?

Editar:Un poco más de razonamiento...No puedo insertar inmediatamente porque el usuario puede terminar cancelando la inserción.El usuario realizará algunos cambios, las declaraciones SQL se almacenarán y desde allí el usuario podrá guardar (insertando todas las filas a la vez) o cancelar (sin cambiar nada).En el caso de una falla del programa, la funcionalidad deseada es que no se cambie nada.

¿Fue útil?

Solución

Desechar o realizar una serie de operaciones de base de datos a la vez es exactamente para lo que sirven las transacciones.Consulta BEGIN; antes de que el usuario comience a tocar el violín y COMMIT; una vez que haya terminado.Tiene la garantía de que se aplicarán todos los cambios (si confirma) o se descartará todo (si consulta ROLLBACK;, si el programa falla, se corta la luz, etc).Una vez que lea desde la base de datos, también tendrá la garantía de que los datos son válidos hasta el final de la transacción, por lo que puede obtener MAX(id) o lo que quieras sin preocuparte por las condiciones de carrera.

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

Otros consejos

Intentar SELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';.Esto contendrá un campo llamado seq que es el número más grande para la tabla seleccionada.Agregue 1 a este valor para obtener la siguiente ID.

Vea también el Artículo de incremento automático de SQLite, de donde proviene la información anterior.

¡Salud!

Probablemente puedas salirte con la tuya agregando 1 al valor devuelto por sqlite3_last_insert_rowid bajo ciertas condiciones, por ejemplo, usando la misma conexión de base de datos y no hay otros escritores simultáneos.Por supuesto, puede consultar el código fuente de sqlite para respaldar estas suposiciones.

Sin embargo, también podría considerar seriamente utilizar un enfoque diferente que no requiera predecir la siguiente ID.Incluso si lo hace bien para la versión de sqlite que está utilizando, las cosas podrían cambiar en el futuro y ciertamente hará que pasar a una base de datos diferente sea más difícil.

Inserte la fila con un indicador NO VÁLIDO de algún tipo, obtenga la identificación, edítela según sea necesario, elimínela si es necesario o márquela como válida.Eso y no te preocupes por los huecos en la secuencia.

Por cierto, tendrás que descubrir cómo hacer tú mismo la parte no válida.Marcar algo como NULL podría funcionar según los detalles.

Editar: Si puede, utilice la sugerencia de Eevee de utilizar transacciones adecuadas.Es mucho menos trabajo.

Me doy cuenta de que su aplicación que usa SQLite es pequeña y SQLite tiene su propia semántica.Otras soluciones publicadas aquí pueden tener el efecto que desea en esta configuración específica, pero en mi opinión, todas y cada una de las que he leído hasta ahora son fundamentalmente incorrectas y deben evitarse.

En un entorno normal, se debe evitar a toda costa realizar una transacción para la entrada del usuario.La forma de manejar esto, si necesita almacenar datos intermedios, es escribir la información en una tabla temporal para este propósito y luego intentar escribir toda la información en una transacción atómica.Realizar transacciones provoca estancamientos y pesadillas de concurrencia en un entorno multiusuario.

En la mayoría de los entornos no se puede asumir que los datos recuperados mediante SELECT dentro de una transacción sean repetibles.Por ejemplo

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

Después de la ACTUALIZACIÓN, es posible que se cambie el valor del saldo.A veces, puede solucionar esto actualizando primero las filas que le interesan en el Banco dentro de una transacción, ya que esto garantiza bloquear la fila evitando que futuras actualizaciones cambien su valor hasta que se haya completado la transacción.

Sin embargo, a veces una mejor manera de garantizar la coherencia en este caso es verificar sus suposiciones sobre el contenido de los datos en la cláusula WHERE de la actualización y verificar el recuento de filas en la aplicación.En el ejemplo anterior, cuando "ACTUALIZA el banco", la cláusula WHERE debe proporcionar el valor actual esperado del saldo:

WHERE Balance = valuefromselect

Si el saldo esperado ya no coincide, tampoco lo hace la condición WHERE: ACTUALIZAR no hace nada y el recuento de filas devuelve 0.Esto le indica que hubo un problema de simultaneidad y que necesita volver a ejecutar la operación cuando algo más no esté intentando cambiar sus datos al mismo tiempo.

select max(id) from particular_table is unreliable for the reason below..

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

"El algoritmo de selección de ROWID normal descrito anteriormente generará ROWID únicos que aumentan monótonamente siempre que nunca utilice el valor máximo de ROWID y nunca elimine la entrada en la tabla con el ROWID más grande.Si alguna vez elimina filas o si alguna vez crea una fila con el máximo ROWID posible, los ROWID de filas previamente eliminadas podrían reutilizarse al crear nuevas filas y los ROWID recién creados podrían no estar en orden estrictamente ascendente".

Creo que esto no se puede hacer porque no hay forma de estar seguro de que no se insertará nada entre la pregunta y la inserción.(Es posible que puedas bloquear la mesa para insertar, pero ¡qué asco!)

Por cierto, solo he usado MySQL pero no creo que eso haga ninguna diferencia)

Lo más probable es que puedas hacer +1 en la identificación más reciente.Miraría todas (retrocediendo un tiempo) las identificaciones existentes en la tabla ordenada.¿Son consistentes y el ID de cada fila es uno más que el anterior?Si es así, probablemente estarás bien.Sin embargo, dejaría un comentario en el código explicando la suposición.Hacer un bloqueo ayudará a garantizar que no obtenga filas adicionales mientras hace esto también.

Seleccione el valor last_insert_rowid().

La mayor parte de todo lo que hay que decir en este tema ya está... Sin embargo, tenga mucho cuidado con las condiciones de carrera. al hacer esto.Si dos personas abren su aplicación/página web/lo que sea, y una de ellas agrega una fila, el otro usuario intentará insertar una fila con la misma ID y tendrá muchos problemas.

select max(id) from particular_table;

La siguiente identificación será +1 de la identificación máxima.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top