¿Por qué necesita crear un cursor cuando consulta una base de datos sqlite?

133

Soy completamente nuevo en el módulo sqlite3 de Python (y SQL en general para el caso), y esto me sorprende por completo. La abundante falta de descripciones de los cursorobjetos (más bien, su necesidad) también parece extraña.

Este fragmento de código es la forma preferida de hacer las cosas:

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

Este no lo es, a pesar de que funciona igual de bien y sin el (aparentemente inútil) cursor:

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

¿Alguien puede decirme por qué necesito un cursor?
Simplemente parece una sobrecarga inútil. Para cada método en mi script que accede a una base de datos, ¿se supone que debo crear y destruir un cursor?
¿Por qué no solo usar el connectionobjeto?

Jack Bauer
fuente

Respuestas:

60

Solo una abstracción mal aplicada me parece. Un cursor db es una abstracción, pensada para el recorrido del conjunto de datos.

Del artículo de Wikipedia sobre el tema :

En informática y tecnología, el cursor de una base de datos es una estructura de control que permite atravesar los registros de una base de datos. Los cursores facilitan el procesamiento posterior junto con el recorrido, como la recuperación, adición y eliminación de registros de la base de datos. La característica del cursor de la base de datos del recorrido hace que los cursores sean similares al concepto de iterador del lenguaje de programación.

Y:

Los cursores no solo se pueden utilizar para obtener datos del DBMS en una aplicación, sino también para identificar una fila en una tabla que se actualizará o eliminará. El estándar SQL: 2003 define la actualización posicionada y las declaraciones SQL de eliminación posicionada para ese propósito. Dichas declaraciones no usan una cláusula WHERE regular con predicados. En cambio, un cursor identifica la fila. El cursor debe estar abierto y ya posicionado en una fila mediante la instrucción FETCH.

Si revisa los documentos en el módulo Python sqlite , puede ver que cursorse necesita un módulo python incluso para una CREATE TABLEdeclaración, por lo que se usa para casos en los que un simple connectionobjeto debería ser suficiente, como lo señala correctamente el OP. Tal abstracción es diferente de lo que la gente entiende que es un cursor db y, por lo tanto, la confusión / frustración de los usuarios. Independientemente de la eficiencia, es solo una sobrecarga conceptual. Sería bueno si se señalara en los documentos que el módulo de Python cursores un poco diferente de lo que es un cursor en SQL y bases de datos.

Basel Shishani
fuente
77
+1 por reconocer la distinción (al principio) muy confusa entre los cursores de base de datos "tradicionales" y los cursores utilizados para una base de datos en Python
Paul Draper
3
En realidad, uno puede simplemente crear una tabla incluso sin usar un cursor .
Serge Stroobandt
38

Necesita un objeto de cursor para obtener resultados. Su ejemplo funciona porque es un INSERTy, por lo tanto, no está tratando de recuperar filas, pero si mira los sqlite3documentos , notará que no hay ningún .fetchXXXXmétodo en los objetos de conexión, por lo que si intentó hacerlo una SELECTsin un cursor, tendría ninguna manera de obtener los datos resultantes.

Los objetos de cursor le permiten realizar un seguimiento de qué conjunto de resultados es cuál, ya que es posible ejecutar múltiples consultas antes de que termine de buscar los resultados de la primera.

Ámbar
fuente
55
También vale la pena tenerlo en cuenta: PEP 249 no define executeen un objeto de conexión, esta es una sqlite3extensión.
Cat Plus Plus
44
Todavía funciona con instrucciones SELECT: pastebin.com/5ZbhfEn7 . La razón es que no está llamando a ningún método .fetchXXXX en el objeto de conexión, está llamando a un método .fetchXXXX en el objeto devuelto por el método .execute () de la conexión.
Jack Bauer
1
Si. Pero una forma de terminar con un cursor (aparentemente) innecesario con el que consultar la base de datos: p
Jack Bauer
2
El uso explícito de los cursores es un buen hábito, ya que probablemente habrá futuros proyectos en los que trabaje donde las cosas no sean de confirmación automática.
Ámbar
1
Lo suficientemente justo. Gracias por la información :)
Jack Bauer
36

Según los documentos oficiales, se connection.execute()trata de un acceso directo no estándar que crea un objeto de cursor intermedio:

Connection.execute
Este es un acceso directo no estándar que crea un objeto cursor al llamar al método cursor (), llama al método execute () del cursor con los parámetros dados y devuelve el cursor.

usuario
fuente
19

12.6.8. Usando sqlite3 eficiente Ly

12.6.8.1. Usar métodos abreviados

Utilizando el estándar execute() , executemany()y executescript()los métodos del objeto de conexión, su código puede ser escrito más concisa mente, ya que no tiene que crear el (a menudo superfluos ) El cursor se opone de forma explícita. En cambio, los objetos del cursor se crean implícitamente y estos métodos de acceso directo devuelven los objetos del cursor. De esta manera, puede ejecutar una instrucción SELECT e iterar sobre ella directamente utilizando solo una llamada en el objeto Connection.

( documentación de sqlite3 ; énfasis mío.)

¿Por qué no solo usar el objeto de conexión?

Debido a que esos métodos del objeto de conexión no son estándar , es decir, no forman parte de la especificación de API Python Database v2.0 (PEP 249).

Siempre que utilice los métodos estándar del objeto Cursor, puede estar seguro de que si cambia a otra implementación de base de datos que siga la especificación anterior, su código será totalmente portátil. Quizás solo necesite cambiar la importlínea.

Pero si usa el, connection.executeexiste la posibilidad de que el cambio no sea tan sencillo. Esa es la razón principal por la que quizás quieras usar cursor.executeen su lugar.

Sin embargo, si está seguro de que no va a cambiar, diría que está completamente bien tomar el connection.executeatajo y ser "eficiente".

AXO
fuente
1

Nos da la capacidad de tener múltiples entornos de trabajo separados a través de la misma conexión a la base de datos.

Python Learner
fuente