Perché è necessario creare un cursore durante l'interrogazione di un database sqlite?


133

Sono completamente nuovo nel modulo sqlite3 di Python (e SQL in generale per quella materia), e questo mi sorprende completamente. Anche l'abbondanza di descrizioni degli cursoroggetti (piuttosto la loro necessità) sembra strana.

Questo frammento di codice è il modo preferito di fare le cose:

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()

Questo non lo è, anche se funziona altrettanto bene e senza (apparentemente inutile) cursor:

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

Qualcuno può dirmi perché ho bisogno di un cursor?
Sembra inutile sovraccarico. Per ogni metodo nel mio script che accede a un database, dovrei creare e distruggere un cursor?
Perché non usare semplicemente l' connectionoggetto?

Risposte:


60

Mi sembra solo un'astrazione erroneamente applicata. Un cursore db è un'astrazione, pensata per l'attraversamento del set di dati.

Da voci di Wikipedia soggetto :

In informatica e tecnologia, un cursore di database è una struttura di controllo che consente l'attraversamento dei record in un database. I cursori facilitano l'elaborazione successiva in combinazione con l'attraversamento, come il recupero, l'aggiunta e la rimozione dei record del database. La caratteristica del cursore del database di traversal rende i cursori simili al concetto di iteratore del linguaggio di programmazione.

E:

I cursori non possono solo essere utilizzati per recuperare i dati dal DBMS in un'applicazione, ma anche per identificare una riga in una tabella da aggiornare o eliminare. Lo standard SQL: 2003 definisce l'aggiornamento posizionato e le istruzioni SQL eliminate posizionate a tale scopo. Tali dichiarazioni non usano una clausola WHERE regolare con predicati. Invece, un cursore identifica la riga. Il cursore deve essere aperto e già posizionato su una riga mediante l'istruzione FETCH.

Se controlli i documenti sul modulo sqlite di Python , puoi vedere che un modulo python cursorè necessario anche per CREATE TABLEun'istruzione, quindi viene usato per i casi in cui un semplice connectionoggetto dovrebbe essere sufficiente, come correttamente sottolineato dall'OP. Tale astrazione è diversa da ciò che le persone comprendono come un cursore db e quindi dalla confusione / frustrazione da parte degli utenti. Indipendentemente dall'efficienza, è solo un sovraccarico concettuale. Sarebbe bello se nei documenti fosse indicato che il modulo Python cursorè leggermente diverso da quello che è un cursore in SQL e database.


7
+1 per aver riconosciuto la (inizialmente) distinzione molto confusa tra i cursori db "tradizionali" e i cursori usati per un db in Python
Paul Draper


38

È necessario un oggetto cursore per recuperare i risultati. Il tuo esempio funziona perché è un INSERTe quindi non stai provando a recuperare alcuna riga da esso, ma se dai un'occhiata ai sqlite3documenti , noterai che non ci sono .fetchXXXXmetodi sugli oggetti di connessione, quindi se hai provato a farlo a SELECTsenza cursore, non avresti modo di ottenere i dati risultanti.

Gli oggetti cursore consentono di tenere traccia di quale set di risultati è quale, poiché è possibile eseguire più query prima di aver completato il recupero dei risultati del primo.


5
Vale anche la pena ricordare: PEP 249 non definisce executeun oggetto connessione, questa è sqlite3un'estensione.
Cat Plus Plus,

4
Funziona ancora con le istruzioni SELECT: pastebin.com/5ZbhfEn7 . Il motivo è che non stai chiamando alcun metodo .fetchXXXX sull'oggetto connessione, stai chiamando un metodo .fetchXXXX sull'oggetto restituito dal metodo .execute () della connessione.
Jack Bauer,

1
Sì. Ma un modo per finire con un cursore (apparentemente) inutile con cui interrogare il database: p
Jack Bauer,

2
L'uso esplicito dei cursori è una buona abitudine, in quanto probabilmente ci saranno progetti futuri su cui lavori in cui le cose non si impegnano automaticamente.
Ambra

1
Giusto. Grazie per le informazioni :)
Jack Bauer,

36

Secondo i documenti ufficiali connection.execute()è un collegamento non standard che crea un oggetto cursore intermedio:

Connection.execute
Questo è un collegamento non standard che crea un oggetto cursore chiamando il metodo cursore (), chiama il metodo execute () del cursore con i parametri indicati e restituisce il cursore.


19

12.6.8. Utilizzando sqlite3 efficiente ly

12.6.8.1. Utilizzando metodi di scelta rapida

Utilizzando la non standard execute() , executemany()e executescript()metodi dell'oggetto Connection, il codice può essere scritto più conciso mente perché non c'è bisogno di creare la (spesso superfluo ) Cursore oggetti in modo esplicito. Al contrario, gli oggetti Cursor vengono creati in modo implicito e questi metodi di scelta rapida restituiscono gli oggetti cursore. In questo modo, è possibile eseguire un'istruzione SELECT e scorrere su di essa direttamente utilizzando una sola chiamata sull'oggetto Connection.

( documentazione sqlite3 ; sottolineatura mia.)

Perché non usare semplicemente l'oggetto connessione?

Poiché tali metodi dell'oggetto connessione non sono standard , ovvero non fanno parte della specifica API del database Python v2.0 (PEP 249).

Finché si utilizzano i metodi standard dell'oggetto Cursor, si può essere certi che se si passa a un'altra implementazione del database che segue le specifiche di cui sopra, il codice sarà completamente portatile. Forse dovrai solo cambiare la importlinea.

Ma se usi la connection.executepossibilità c'è che il passaggio non sarà così semplice. Questo è il motivo principale che potresti voler usare cursor.executeinvece.

Tuttavia, se sei sicuro di non cambiare, direi che è completamente OK prendere la connection.executescorciatoia ed essere "efficiente".


1

Ci dà la possibilità di avere più ambienti di lavoro separati attraverso la stessa connessione al database.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.