Pourquoi avez-vous besoin de créer un curseur lors de l'interrogation d'une base de données sqlite?

133

Je suis complètement nouveau dans le module sqlite3 de Python (et SQL en général d'ailleurs), et cela me laisse complètement perplexe . Le manque abondant de descriptions d' cursorobjets (plutôt leur nécessité) semble également étrange.

Cet extrait de code est la manière préférée de faire les choses:

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

Celui-ci ne l'est pas, même s'il fonctionne aussi bien et sans le (apparemment inutile) cursor:

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

Quelqu'un peut-il me dire pourquoi j'ai besoin d'un cursor?
Cela semble juste comme des frais généraux inutiles. Pour chaque méthode de mon script qui accède à une base de données, je suis censé créer et détruire un cursor?
Pourquoi ne pas simplement utiliser l' connectionobjet?

Jack Bauer
la source

Réponses:

60

Juste une abstraction mal appliquée, me semble-t-il. Un curseur de base de données est une abstraction, destinée à la traversée de l'ensemble de données.

De l'article de Wikipédia sur le sujet :

En informatique et en technologie, un curseur de base de données est une structure de contrôle qui permet de parcourir les enregistrements d'une base de données. Les curseurs facilitent le traitement ultérieur en conjonction avec la traversée, comme la récupération, l'ajout et la suppression d'enregistrements de base de données. La caractéristique de curseur de base de données de la traversée rend les curseurs similaires au concept du langage de programmation d'itérateur.

Et:

Les curseurs peuvent non seulement être utilisés pour récupérer des données du SGBD dans une application, mais également pour identifier une ligne dans une table à mettre à jour ou à supprimer. La norme SQL: 2003 définit la mise à jour positionnée et les instructions SQL de suppression positionnées à cet effet. De telles instructions n'utilisent pas de clause WHERE régulière avec des prédicats. Au lieu de cela, un curseur identifie la ligne. Le curseur doit être ouvert et déjà positionné sur une ligne au moyen de l'instruction FETCH.

Si vous consultez la documentation sur le module sqlite de Python , vous pouvez voir qu'un module python cursorest nécessaire même pour une CREATE TABLEinstruction, il est donc utilisé pour les cas où un simple connectionobjet devrait suffire - comme indiqué correctement par l'OP. Une telle abstraction est différente de ce que les gens comprennent comme étant un curseur de base de données et par conséquent, la confusion / frustration de la part des utilisateurs. Indépendamment de l'efficacité, il ne s'agit que d'une surcharge conceptuelle. Ce serait bien s'il était indiqué dans la documentation que le module python cursorest un peu différent de ce qu'est un curseur dans SQL et les bases de données.

Bâle Shishani
la source
7
+1 pour avoir reconnu la distinction (au début) très confuse entre les curseurs de base de données "traditionnels" et les curseurs utilisés pour une base de données en Python
Paul Draper
3
En fait, on peut simplement créer une table sans utiliser de curseur .
Serge Stroobandt
38

Vous avez besoin d'un objet curseur pour récupérer les résultats. Votre exemple fonctionne parce que c'est un INSERTet que vous n'essayez donc pas de récupérer des lignes, mais si vous regardez la sqlite3documentation , vous remarquerez qu'il n'y a aucune .fetchXXXXméthode sur les objets de connexion, donc si vous avez essayé de le faire a SELECTsans curseur, vous n'auriez aucun moyen d'obtenir les données résultantes.

Les objets Cursor vous permettent de garder une trace de quel jeu de résultats est lequel, car il est possible d'exécuter plusieurs requêtes avant d'avoir fini de récupérer les résultats de la première.

ambre
la source
5
Il convient également de garder à l'esprit: PEP 249 ne définit pas executesur un objet de connexion, il s'agit d'une sqlite3extension.
Cat Plus Plus
4
Cela fonctionne toujours avec les instructions SELECT: pastebin.com/5ZbhfEn7 . La raison étant que vous n'appelez aucune méthode .fetchXXXX sur l'objet de connexion, vous appelez une méthode .fetchXXXX sur l'objet renvoyé par la méthode .execute () de la connexion.
Jack Bauer
1
Oui. Mais une façon dont vous vous retrouvez avec un curseur (apparemment) inutile pour interroger la base de données: p
Jack Bauer
2
L'utilisation explicite des curseurs est une bonne habitude à prendre, car il y aura probablement des projets futurs sur lesquels vous travaillez où les choses ne sont pas auto-validées.
Amber
1
C'est suffisant. Merci pour l'info :)
Jack Bauer
36

Selon la documentation officielle, il connection.execute()existe un raccourci non standard qui crée un objet curseur intermédiaire:

Connection.execute
Il s'agit d'un raccourci non standard qui crée un objet curseur en appelant la méthode cursor (), appelle la méthode execute () du curseur avec les paramètres donnés et renvoie le curseur.

utilisateur
la source
19

12.6.8. Utilisation de sqlite3 efficace ly

12.6.8.1. Utilisation de méthodes de raccourci

Utilisation de la non - standard execute() , executemany()et les executescript()méthodes de l'objet de connexion, votre code peut être écrit plus concis ment parce que vous ne devez pas créer le (souvent superflu ) des objets curseur explicitement. Au lieu de cela, les objets Cursor sont créés implicitement et ces méthodes de raccourci renvoient les objets curseur. De cette façon, vous pouvez exécuter une instruction SELECT et effectuer une itération dessus directement en utilisant un seul appel sur l'objet Connection.

( documentation sqlite3 ; c'est moi qui souligne.)

Pourquoi ne pas simplement utiliser l'objet de connexion?

Parce que ces méthodes de l'objet de connexion ne sont pas standard , c'est-à-dire qu'elles ne font pas partie de la spécification de l'API de base de données Python v2.0 (PEP 249).

Tant que vous utilisez les méthodes standard de l'objet Cursor, vous pouvez être sûr que si vous passez à une autre implémentation de base de données qui suit la spécification ci-dessus, votre code sera entièrement portable. Il vous suffira peut-être de changer leimport ligne.

Mais si vous utilisez le, connection.executeil est possible que le changement ne soit pas aussi simple. C'est la raison principale pour laquelle vous voudrez peut-être utiliser à la cursor.executeplace.

Cependant, si vous êtes certain que vous n'allez pas changer, je dirais que c'est tout à fait OK de prendre le connection.executeraccourci et d'être "efficace".

AXO
la source
1

Cela nous donne la possibilité d'avoir plusieurs environnements de travail séparés via la même connexion à la base de données.

Apprenant Python
la source