Warum müssen Sie beim Abfragen einer SQLite-Datenbank einen Cursor erstellen?

133

Ich bin völlig neu in Pythons sqlite3-Modul (und SQL im Allgemeinen), und das macht mich einfach total fertig. Das reichlich vorhandene Fehlen von Beschreibungen von cursorObjekten (eher deren Notwendigkeit) scheint ebenfalls seltsam.

Dieser Codeausschnitt ist die bevorzugte Methode, um Dinge zu tun:

import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()

Dies ist nicht der Fall, obwohl es genauso gut und ohne das (scheinbar sinnlose) funktioniert cursor:

import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()

Kann mir jemand sagen, warum ich eine brauche cursor?
Es scheint nur sinnlos über Kopf. Für jede Methode in meinem Skript, die auf eine Datenbank zugreift, soll ich ein cursor? Erstellen und zerstören .
Warum nicht einfach das connectionObjekt benutzen ?

Jack Bauer
quelle

Antworten:

60

Nur eine falsch angewandte Abstraktion scheint mir. Ein DB-Cursor ist eine Abstraktion, die zum Durchlaufen von Datensätzen gedacht ist.

Aus dem Wikipedia-Artikel zum Thema :

In der Informatik und Technologie ist ein Datenbankcursor eine Kontrollstruktur, die das Durchlaufen der Datensätze in einer Datenbank ermöglicht. Cursor erleichtern die nachfolgende Verarbeitung in Verbindung mit dem Durchlaufen, z. B. das Abrufen, Hinzufügen und Entfernen von Datenbankeinträgen. Die Datenbank-Cursor-Eigenschaft von Traversal macht Cursor ähnlich dem Programmiersprachenkonzept des Iterators.

Und:

Cursor können nicht nur zum Abrufen von Daten aus dem DBMS in eine Anwendung verwendet werden, sondern auch zum Identifizieren einer Zeile in einer Tabelle, die aktualisiert oder gelöscht werden soll. Der SQL: 2003-Standard definiert zu diesem Zweck positionierte Aktualisierungs- und gelöschte Lösch-SQL-Anweisungen. Solche Anweisungen verwenden keine reguläre WHERE-Klausel mit Prädikaten. Stattdessen identifiziert ein Cursor die Zeile. Der Cursor muss mittels FETCH-Anweisung geöffnet und bereits in einer Zeile positioniert sein.

Wenn Sie die Dokumente im Python-SQLite-Modul überprüfen , können Sie feststellen, dass ein Python-Modul cursorauch für eine CREATE TABLEAnweisung benötigt wird. Daher wird es in Fällen verwendet, in denen ein bloßes connectionObjekt ausreichen sollte - wie vom OP korrekt hervorgehoben. Eine solche Abstraktion unterscheidet sich von dem, was Menschen unter einem DB-Cursor verstehen, und damit von der Verwirrung / Frustration der Benutzer. Unabhängig von der Effizienz ist dies nur ein konzeptioneller Aufwand. Wäre schön, wenn in den Dokumenten darauf hingewiesen würde, dass das Python-Modul cursoretwas anders ist als ein Cursor in SQL und Datenbanken.

Basel Shishani
quelle
7
+1 für die Anerkennung der (zunächst) sehr verwirrenden Unterscheidung zwischen "traditionellen" Datenbankcursorn und den für eine Datenbank in Python verwendeten Cursorn
Paul Draper
3
Tatsächlich kann man auch ohne Cursor einfach eine Tabelle erstellen .
Serge Stroobandt
38

Sie benötigen ein Cursorobjekt, um Ergebnisse abzurufen. Ihr Beispiel funktioniert, weil es ein ist INSERTund Sie daher nicht versuchen, Zeilen daraus zurückzugewinnen. Wenn Sie sich jedoch die sqlite3Dokumente ansehen , werden Sie feststellen, dass es keine .fetchXXXXMethoden für Verbindungsobjekte gibt. Wenn Sie dies also versucht haben a SELECTOhne Cursor haben Sie keine Möglichkeit, die resultierenden Daten abzurufen.

Mit Cursorobjekten können Sie verfolgen, welche Ergebnismenge welche ist, da mehrere Abfragen ausgeführt werden können, bevor Sie die Ergebnisse der ersten abrufen.

Bernstein
quelle
5
Beachten Sie auch: PEP 249 definiert executekein Verbindungsobjekt, dies ist eine sqlite3Erweiterung.
Cat Plus Plus
4
Es funktioniert weiterhin mit SELECT-Anweisungen: pastebin.com/5ZbhfEn7 . Der Grund dafür ist, dass Sie keine .fetchXXXX-Methoden für das Verbindungsobjekt aufrufen, sondern eine .fetchXXXX-Methode für das Objekt, das von der .execute () -Methode der Verbindung zurückgegeben wird.
Jack Bauer
1
Ja. Aber eine Möglichkeit, einen (scheinbar) unnötigen Cursor zu erhalten, mit dem Sie die Datenbank abfragen können: p
Jack Bauer
2
Die explizite Verwendung von Cursorn ist eine gute Angewohnheit, da es wahrscheinlich zukünftige Projekte geben wird, an denen Sie arbeiten, bei denen die Dinge nicht automatisch festgeschrieben werden.
Amber
1
Meinetwegen. Danke für die Info :)
Jack Bauer
36

Laut den offiziellen Dokumenten connection.execute() handelt es sich um eine nicht standardmäßige Verknüpfung , die ein Zwischencursorobjekt erstellt:

Connection.execute
Dies ist eine nicht standardmäßige Verknüpfung, die ein Cursorobjekt durch Aufrufen der cursor () -Methode erstellt, die execute () -Methode des Cursors mit den angegebenen Parametern aufruft und den Cursor zurückgibt.

Benutzer
quelle
19

12.6.8. Mit sqlite3 effizient ly

12.6.8.1. Mit Verknüpfung Methoden

Unter Verwendung des Nicht - Standard execute() , executemany()und executescript()Methoden des Connection - Objekts, kann Ihr Code geschrieben werden prägnante ly , weil Sie müssen die (oft nicht erstellen überflüssig ) Cursor explizit Objekte. Stattdessen werden die Cursorobjekte implizit erstellt und diese Verknüpfungsmethoden geben die Cursorobjekte zurück. Auf diese Weise können Sie eine SELECT-Anweisung ausführen und mit nur einem einzigen Aufruf des Connection-Objekts direkt darüber iterieren.

( SQLite3-Dokumentation ; Schwerpunkt Mine.)

Warum nicht einfach das Verbindungsobjekt verwenden?

Da diese Methoden des Verbindungsobjekts nicht dem Standard entsprechen , dh nicht Teil der Python Database API Specification v2.0 (PEP 249) sind.

Solange Sie die Standardmethoden des Cursor-Objekts verwenden, können Sie sicher sein, dass Ihr Code vollständig portierbar ist, wenn Sie zu einer anderen Datenbankimplementierung wechseln, die der obigen Spezifikation folgt. Vielleicht müssen Sie nur die importZeile ändern .

Wenn Sie das verwenden, besteht jedoch die connection.executeMöglichkeit, dass das Umschalten nicht so einfach ist. Dies ist der Hauptgrund, warum Sie cursor.executestattdessen verwenden möchten .

Wenn Sie jedoch sicher sind, dass Sie nicht wechseln werden, würde ich sagen, dass es völlig in Ordnung ist, die connection.executeVerknüpfung zu verwenden und "effizient" zu sein.

AXO
quelle
1

Es gibt uns die Möglichkeit, mehrere separate Arbeitsumgebungen über dieselbe Verbindung zur Datenbank zu haben.

Python-Lerner
quelle