Domanda

Sto cercando di scoprire se esiste un modo affidabile (utilizzando SQLite ) per trovare l'ID della riga successiva da inserire, prima che venga inserita . Devo usare l'id per un'altra istruzione insert, ma non ho la possibilità di inserire e ottenere immediatamente la riga successiva.

Prevedere l'id successivo è semplice come ottenere l'ultimo id e aggiungerne uno? È una garanzia?

Modifica: un po 'più di ragionamento ... Non riesco a inserire immediatamente perché l'inserimento potrebbe essere annullato dall'utente. L'utente effettuerà alcune modifiche, le istruzioni SQL verranno archiviate e da lì l'utente potrà salvare (inserendo tutte le righe contemporaneamente) o annullare (senza modificare nulla). In caso di arresto anomalo del programma, la funzionalità desiderata è che nulla viene modificato.

È stato utile?

Soluzione

Scartare o eseguire una serie di operazioni di database contemporaneamente è esattamente ciò a cui servono le transazioni. Interroga INIZIA; prima che l'utente inizi a giocherellare e COMMIT; una volta che ha finito. Hai la garanzia che tutte le modifiche vengano applicate (se esegui il commit) o ??che tutto venga eliminato (se esegui una query su ROLLBACK; , se il programma si arresta in modo anomalo, l'alimentazione si interrompe, ecc.). Dopo aver letto dal db, hai anche la certezza che i dati siano buoni fino alla fine della transazione, quindi puoi prendere MAX (id) o qualunque cosa tu voglia senza preoccuparti delle condizioni della gara.

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

Altri suggerimenti

Prova SELEZIONA * DA SQLITE_SEQUENCE DOVE name = 'TABLE'; . Questo conterrà un campo chiamato seq che è il numero più grande per la tabella selezionata. Aggiungi 1 a questo valore per ottenere l'ID successivo.

Vedi anche articolo sull'incremento automatico di SQLite , da dove provengono le informazioni di cui sopra.

Cheers!

Probabilmente puoi evitare di aggiungere 1 al valore restituito da sqlite3_last_insert_rowid in determinate condizioni , ad esempio, utilizzando la stessa connessione al database e non esistono altri writer simultanei. Naturalmente, è possibile fare riferimento al codice sorgente sqlite per eseguire il backup di questi presupposti.

Tuttavia, potresti anche prendere seriamente in considerazione l'utilizzo di un approccio diverso che non richiede la previsione dell'ID successivo. Anche se lo ottieni correttamente per la versione di sqlite che stai utilizzando, le cose potrebbero cambiare in futuro e renderebbe sicuramente più difficile il passaggio a un database diverso.

Inserisci la riga con un flag INVALID di qualche tipo, ottieni l'ID, modificalo, se necessario, elimina se necessario o contrassegna come valido. Questo e non preoccuparti delle lacune nella sequenza

A proposito, dovrai capire come fare tu stesso la parte non valida. Contrassegnare qualcosa come NULL potrebbe funzionare a seconda delle specifiche.

Modifica: Se puoi, usa il suggerimento di Eevee di usare le transazioni appropriate. È molto meno lavoro.

Mi rendo conto che l'applicazione che utilizza SQLite è piccola e SQLite ha una sua semantica. Altre soluzioni pubblicate qui potrebbero avere l'effetto desiderato in questa specifica impostazione, ma a mio avviso ognuna di quelle che ho letto finora è fondamentalmente errata e dovrebbe essere evitata.

In un ambiente normale, una transazione per l'input dell'utente dovrebbe essere evitata a tutti i costi. Il modo per gestirlo, se è necessario memorizzare dati intermedi, è quello di scrivere le informazioni in una tabella scratch per questo scopo e quindi tentare di scrivere tutte le informazioni in una transazione atomica. Le transazioni in sospeso invitano deadlock e incubi di concorrenza in un ambiente multiutente.

Nella maggior parte degli ambienti non è possibile ritenere che i dati recuperati tramite SELECT all'interno di una transazione siano ripetibili. Ad esempio

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

Dopo AGGIORNAMENTO, il valore del saldo potrebbe essere modificato. A volte puoi aggirare questo problema aggiornando prima le righe che ti interessano in Banca all'interno di una transazione in quanto questo è garantito per bloccare la riga impedendo ad ulteriori aggiornamenti di modificarne il valore fino al completamento della transazione.

Tuttavia, a volte un modo migliore per garantire la coerenza in questo caso è quello di controllare le tue ipotesi sul contenuto dei dati nella clausola WHERE dell'aggiornamento e controllare il conteggio delle righe nell'applicazione. Nell'esempio sopra quando "AGGIORNA Banca" la clausola WHERE dovrebbe fornire il valore attuale atteso del saldo:

WHERE Balance = valuefromselect

Se il saldo previsto non corrisponde più, né la condizione WHERE - UPDATE non fa nulla e il conteggio delle righe restituisce 0. Questo ti dice che c'era un problema di concorrenza e che devi ripetere l'operazione quando qualcos'altro non sta cercando di cambiare i tuoi dati allo stesso tempo.

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

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

" Il normale algoritmo di selezione ROWID sopra descritto genererà ROWID unici monotonicamente crescenti purché non si usi mai il valore ROWID massimo e non si cancella mai la voce nella tabella con il ROWID più grande. Se elimini mai delle righe o se crei una riga con il massimo ROWID possibile, i ROWID dalle righe precedentemente eliminate potrebbero essere riutilizzati durante la creazione di nuove righe e i ROWID appena creati potrebbero non essere in ordine strettamente crescente. & Quot;

Penso che questo non possa essere fatto perché non c'è modo di essere sicuri che nulla verrà inserito tra la tua richiesta e l'inserimento. (potresti essere in grado di bloccare la tabella con inserti ma Yuck)

A proposito, ho usato solo MySQL ma non penso che farà alcuna differenza)

Molto probabilmente dovresti essere in grado di fare +1 sull'ID più recente. Vorrei esaminare tutti (risalendo un po ') degli ID esistenti nella tabella ordinata. Sono coerenti e l'ID di ogni riga è uno in più dell'ultimo? Se è così, probabilmente starai bene. Lascerei comunque commenti nel codice che spiegano l'assunzione. Fare un lucchetto ti aiuterà a non ricevere righe aggiuntive mentre lo fai anche tu.

Seleziona il valore last_insert_rowid ().

La maggior parte di tutto ciò che deve essere detto in questo argomento ha già ... Tuttavia, fai molta attenzione alle condizioni di gara quando lo fai. Se due persone aprono la tua applicazione / pagina web / qualunque cosa, e una di esse aggiunge una riga, l'altro utente proverà a inserire una riga con lo stesso ID e avrai molti problemi.

select max(id) from particular_table;

L'ID successivo sarà +1 dall'ID massimo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top