2012-11-06 8 views
7

Ich habe einige Zeit mit dem Lesen der SQLite docs, verschiedene Fragen und Antworten hier auf Stack Overflow und this thing verbracht, aber nicht zu einer vollständigen Antwort gekommen.SQLite einfügen oder ignorieren und original _rowid_

Ich weiß, dass es keine Möglichkeit gibt, so etwas wie INSERT OR IGNORE INTO foo VALUES(...) mit SQLite zu tun, und der Nummer der ursprünglichen Reihe zurück, und dass in der Nähe von ihm wäre INSERT OR REPLACEaber das löscht die gesamte Zeile und fügt eine neue Zeile und erhält also eine neue rowid.

Beispieltabelle

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

Im Moment kann ich tun:

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] 

Aber etwas ideal würde so aussehen:

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

Was das Beste ist (sprich: die meisten effiziente Möglichkeit, eine Zeile in eine Tabelle einzufügen und die Zeilennummer zurückzugeben oder die Zeile zu ignorieren, wenn i t existiert schon und bekomme einfach die rowid? Effizienz ist wichtig, weil dies oft passiert.

Gibt es einen Weg zu INSERT OR IGNORE und gibt die rowid der Zeile zurück, mit der die ignorierte Zeile verglichen wurde? Das wäre toll, denn es wäre genauso effizient wie ein Insert.

+1

Haben Sie 'UPDATE ... WHERE ...' versucht? – Keith

Antwort

6

Der Weg, der am besten für mich arbeitete, war insert or ignore die Werte, und die select die Rowid in zwei separaten Schritten. Ich verwendete eine unique Einschränkung auf der data Spalte, um sowohl Selektionen zu beschleunigen als auch Duplikate zu vermeiden.

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

Die select Aussage ist nicht so langsam, wie ich dachte, es wäre. Dies ist it seems, weil SQLite automatisch einen Index für die Spalten unique erstellt.

1

INSERT OR IGNORE ist für Situationen, in denen Sie sich nicht um die Identität des Datensatzes kümmern; wo das Ziel ist nur einige Rekord mit diesem spezifischen Wert zu haben.

Wenn Sie, ob ein neuer Datensatz wissen wollen, eingeführt ist oder nicht, müssen Sie von Hand überprüfen:

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 

Bezüglich Effizienz: Wenn SQLite die data Spalte für Duplikate überprüft, hat es genau das zu tun die gleiche Abfrage, die Sie mit der SELECT tun, und sobald Sie das getan haben, ist der Zugriffspfad im Cache, so dass die Leistung kein Problem sein sollte. In jedem Fall ist es ist notwendig, um zwei separate INSERT/SELECT Abfragen (in jeder Reihenfolge, sowohl Ihre und mein Code arbeiten, aber Ihre ist einfacher).

Verwandte Themen