Prédire le prochain identifiant de ligne inséré automatiquement (SQLite)

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

  •  01-07-2019
  •  | 
  •  

Question

J'essaie de trouver un moyen fiable (à l'aide de SQLite ) de rechercher l'identifiant de la prochaine ligne à insérer, avant qu'elle ne soit insérée . Je dois utiliser l'identifiant pour une autre instruction d'insertion, mais je n'ai pas la possibilité d'insérer instantanément et d'obtenir la ligne suivante.

Prédire le prochain identifiant est-il aussi simple que d’obtenir le dernier identifiant et d’en ajouter un? Est-ce une garantie?

Edit: Un peu plus de raisonnement ... Je ne peux pas insérer immédiatement car l'insertion risque d'être annulée par l'utilisateur. L'utilisateur apportera des modifications, les instructions SQL seront stockées et à partir de là, l'utilisateur pourra soit sauvegarder (insérer toutes les lignes à la fois), soit annuler (ne rien changer). En cas de blocage du programme, la fonctionnalité souhaitée est que rien ne soit changé.

Était-ce utile?

La solution

Le fait de mettre au rebut ou de valider une série d'opérations de base de données est exactement ce à quoi servent les transactions. Interrogez BEGIN; avant que l'utilisateur ne commence à tripoter et COMMIT; une fois qu'il / elle a terminé. Vous avez la garantie que toutes les modifications sont appliquées (si vous validez) ou que tout est mis au rebut (si vous interrogez ROLLBACK; , si le programme se bloque, le système s'éteint, etc.). Une fois que vous avez lu la base de données, vous êtes également assuré que les données sont valables jusqu’à la fin de la transaction. Vous pouvez ainsi récupérer MAX (id) ou tout autre contenu sans vous soucier des conditions de concurrence.

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

Autres conseils

Essayez SELECT * FROM SQLITE_SEQUENCE WHERE name = 'TABLE'; . Cela contiendra un champ appelé seq qui est le plus grand nombre pour la table sélectionnée. Ajoutez 1 à cette valeur pour obtenir l'ID suivant.

Voir également le article d'auto-incrémentation de SQLite , d'où proviennent les informations ci-dessus.

Salut!

Vous pouvez probablement vous contenter d'ajouter 1 à la valeur renvoyée par sqlite3_last_insert_rowid dans certaines conditions. Par exemple, si vous utilisez la même connexion à la base de données et qu’il n’ya pas d’autre rédacteur simultané. Bien entendu, vous pouvez vous référer au code source de SQLite pour sauvegarder ces hypothèses.

Cependant, vous pouvez également envisager sérieusement d’utiliser une approche différente qui ne nécessite pas de prédire le prochain ID. Même si vous utilisez la version de SQLite que vous utilisez, la situation pourrait changer et il sera certainement plus difficile de passer à une autre base de données.

Insérez la ligne avec un indicateur INVALID, Obtenez l’ID, modifiez-la si nécessaire, supprimez-la si nécessaire ou marquez-la comme valide. Cela et ne vous inquiétez pas des lacunes dans la séquence

BTW, vous aurez besoin de savoir comment faire la partie invalide vous-même. Marquer quelque chose comme NULL peut fonctionner selon les spécificités.

Éditer: Si vous le pouvez, utilisez la suggestion d'Eevee d'utiliser les transactions appropriées. C'est beaucoup moins de travail.

Je réalise que votre application utilisant SQLite est petite et que SQLite a sa propre sémantique. Les autres solutions publiées ici pourraient bien avoir l’effet souhaité dans ce contexte spécifique, mais à mon avis, chacune d’entre elles que j’ai lues jusqu’à présent est fondamentalement incorrecte et doit être évitée.

Dans un environnement normal, la transaction doit être évitée à tout prix. Si vous devez stocker des données intermédiaires, la solution consiste à écrire les informations dans une table de travail à cet effet, puis à essayer d’écrire toutes les informations d’une transaction atomique. La mise en attente de transactions entraîne des blocages et des cauchemars de concurrence dans un environnement multi-utilisateurs.

Dans la plupart des environnements, vous ne pouvez pas supposer que les données récupérées via SELECT dans une transaction sont répétables. Par exemple

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

Après UPDATE, la valeur du solde peut bien être modifiée. Parfois, vous pouvez contourner ce problème en mettant à jour la ou les lignes qui intéressent Bank en premier dans une transaction, car il est garanti que la ligne sera verrouillée, empêchant ainsi les mises à jour ultérieures de modifier sa valeur jusqu'à la fin de votre transaction.

Cependant, dans ce cas, un meilleur moyen de garantir la cohérence est de vérifier vos hypothèses sur le contenu des données dans la clause WHERE de la mise à jour et de vérifier le nombre de lignes dans l'application. Dans l'exemple ci-dessus, lorsque vous " UPDATE Bank " la clause WHERE doit fournir la valeur actuelle attendue du solde:

WHERE Balance = valuefromselect

Si le solde attendu ne correspond plus à la condition WHERE - UPDATE ne fait rien et rowcount renvoie 0. Cela vous indique qu'il y a un problème de simultanéité et que vous devez réexécuter l'opération lorsque quelque chose d'autre n'essaie pas de changer. vos données en même temps.

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

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

" L'algorithme de sélection ROWID normal décrit ci-dessus générera des ROWID uniques augmentant de façon monotone tant que vous n'utilisez jamais la valeur ROWID maximale et que vous ne supprimez jamais l'entrée de la table avec le plus grand ROWID. Si vous supprimez des lignes ou si vous créez des lignes avec le ROWID maximal possible, les ROWID des lignes précédemment supprimées peuvent être réutilisés lors de la création de nouvelles lignes et les nouveaux ROWID créés peuvent ne pas être dans un ordre strictement croissant. "

Je pense que cela ne peut être fait car il n’ya aucun moyen de s’assurer que rien ne sera inséré entre vous demander et vous insérer. (vous pouvez peut-être verrouiller la table pour insérer des insertions, mais beurk)

BTW, je n’ai utilisé que MySQL mais je ne pense pas que cela fera une différence)

Très probablement, vous devriez être capable de +1 l'id le plus récent. Je regarderais tous (remontant un peu en arrière) des identifiants existants dans la table ordonnée. Sont-ils cohérents et l'ID de chaque ligne est-il un de plus que le dernier? Si c'est le cas, vous irez probablement bien. Je laisserais un commentaire dans le code expliquant l'hypothèse cependant. Faire un verrou aidera à garantir que vous n'obtiendrez pas de lignes supplémentaires pendant que vous le faites également.

Sélectionnez la valeur last_insert_rowid ().

La plupart de tout ce qui doit être dit dans ce sujet a déjà ... Cependant, faites très attention aux conditions de course lorsque vous agissez ainsi. Si deux personnes ouvrent votre application / page Web / quoi que ce soit, et que l'une d'elles ajoute une ligne, l'autre utilisateur essaiera d'insérer une ligne avec le même identifiant et vous aurez de nombreux problèmes.

select max(id) from particular_table;

Le prochain identifiant sera +1 à partir de l'identifiant maximum.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top