2012-11-06 14 views
7

Ho passato un po 'di tempo a leggere il numero docs di SQLite, varie domande e risposte qui su Stack Overflow e this thing, ma non sono arrivato a una risposta completa.SQLite inserire o ignorare e restituire originale _rowid_

So che non esiste un modo per fare qualcosa di simile INSERT OR IGNORE INTO foo VALUES(...) con SQLite e tornare l'identificativo della riga originale, e che il più vicino ad esso sarebbe INSERT OR REPLACEma che elimina l'intera riga e inserisce una nuova riga e ottiene così un nuovo rowid.

tabella Esempio:

CREATE TABLE foo(
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    data TEXT 
); 

In questo momento mi può fare:

sql = sqlite3.connect(":memory:") 
# create database 
sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);", ("Some text.",)) 
the_id_of_the_row = None 
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ("Some text.",)): 
    the_id_of_the_row = row[0] 

Ma qualcosa di ideale sarebbe simile:

the_id_of_the_row = sql.execute("INSERT OR IGNORE foo(data) VALUES(?)", ("Some text",)).lastrowid 

Qual è la migliore (leggi: più efficiente) modo di inserire una riga in una tabella e restituire il rowid, o di ignorare la riga se io esiste già e basta avere il rowid? L'efficienza è importante perché questo accadrà abbastanza spesso.

C'è un modo per INSERT OR IGNORE e restituire il rowid della riga a cui è stata confrontata la riga ignorata? Sarebbe fantastico, perché sarebbe altrettanto efficiente di un inserto.

+1

Hai provato "AGGIORNAMENTO ... DOVE ..."? – Keith

risposta

6

Il modo migliore per me è stato quello di immettere i valori in insert or ignore e lo select in due passaggi separati. Ho utilizzato un vincolo unique sulla colonna data per accelerare le selezioni ed evitare duplicati.

sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);" ("Some text.",)) 
last_row_id = sql.execute("SELECT id FROM foo WHERE data = ?;" ("Some text. ",)) 

Il select affermazione non è lento come ho pensato che sarebbe stato. Questo, it seems, è dovuto al fatto che SQLite crea automaticamente un indice per le colonne unique.

1

INSERT OR IGNORE è per le situazioni in cui non ti interessa l'identità del record; dove l'obiettivo è di avere solo un record con quel valore specifico.

Se vuoi sapere se un nuovo record viene inserito o meno, si controlla a mano:

the_id_of_the_row = None 
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ...): 
    the_id_of_the_row = row[0] 
if the_id_of_the_row is None: 
    c = sql.cursor() 
    c.execute("INSERT INTO foo(data) VALUES(?)", ...) 
    the_id_of_the_row = c.lastrowid 

Per quanto riguarda l'efficienza: quando SQLite controlla la colonna data di duplicati, ha a che fare esattamente la stessa query che stai facendo con lo SELECT, e una volta fatto, il percorso di accesso è nella cache, quindi le prestazioni non dovrebbero essere un problema. In ogni caso, è è necessario per eseguire due distinte query INSERT/SELECT (in entrambi gli ordini, sia il codice che il mio codice funzionano, ma il tuo è più semplice).

Problemi correlati