Por que você precisa criar um cursor ao consultar um banco de dados sqlite?

133

Eu sou completamente novo no módulo sqlite3 do Python (e SQL em geral), e isso me surpreende completamente. A abundante falta de descrições de cursorobjetos (antes, sua necessidade) também parece estranha.

Esse trecho de código é a maneira preferida de fazer as coisas:

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 não é, mesmo que funcione tão bem e sem o (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()

Alguém pode me dizer por que eu preciso de um cursor?
Parece sobrecarga inútil. Para cada método no meu script que acessa um banco de dados, devo criar e destruir um cursor?
Por que não usar apenas o connectionobjeto?

Jack Bauer
fonte

Respostas:

60

Apenas uma abstração mal aplicada parece-me. Um cursor db é uma abstração, destinada à passagem do conjunto de dados.

Do artigo da Wikipedia sobre o assunto :

Em ciência e tecnologia da computação, um cursor de banco de dados é uma estrutura de controle que permite a travessia dos registros em um banco de dados. Os cursores facilitam o processamento subsequente em conjunto com a passagem, como recuperação, adição e remoção de registros do banco de dados. A característica do cursor do banco de dados do traversal torna os cursores semelhantes ao conceito de linguagem de programação do iterador.

E:

Os cursores não podem ser usados ​​apenas para buscar dados do DBMS em um aplicativo, mas também para identificar uma linha em uma tabela a ser atualizada ou excluída. O padrão SQL: 2003 define atualização posicionada e instruções SQL de exclusão posicionada para esse fim. Tais instruções não usam uma cláusula WHERE regular com predicados. Em vez disso, um cursor identifica a linha. O cursor deve estar aberto e já posicionado em uma linha por meio da instrução FETCH.

Se você verificar os documentos no módulo sqlite do Python , poderá ver que um módulo python cursoré necessário mesmo para uma CREATE TABLEinstrução, portanto, é usado nos casos em que um mero connectionobjeto deve ser suficiente - conforme indicado corretamente pelo OP. Essa abstração é diferente do que as pessoas entendem ser um cursor db e, portanto, a confusão / frustração por parte dos usuários. Independentemente da eficiência, é apenas uma sobrecarga conceitual. Seria bom se fosse indicado nos documentos que o módulo python cursoré um pouco diferente do que o cursor é no SQL e nos bancos de dados.

Basel Shishani
fonte
7
1 para reconhecimento da (em primeiro lugar) muito confusa distinção entre "tradicionais" cursores db e os cursores utilizados para um db em Python
Paul Draper
3
Na verdade, pode-se simplesmente criar uma tabela mesmo sem o uso de um cursor .
Serge Stroobandt
38

Você precisa de um objeto cursor para buscar resultados. Seu exemplo funciona porque é um INSERTe, portanto, você não está tentando recuperar nenhuma linha, mas se você olhar para os sqlite3documentos , perceberá que não existem .fetchXXXXmétodos nos objetos de conexão; portanto, se você tentou fazer isso um SELECTsem um cursor, você não teria nenhuma maneira de obter os dados resultantes.

Os objetos de cursor permitem que você acompanhe qual conjunto de resultados é qual, já que é possível executar várias consultas antes de concluir a busca dos resultados da primeira.

Âmbar
fonte
5
Também vale lembrar: o PEP 249 não define executeem um objeto de conexão, esta é uma sqlite3extensão.
Cat Plus Plus
4
Ele ainda funciona com instruções SELECT: pastebin.com/5ZbhfEn7 . O motivo é que você não está chamando nenhum método .fetchXXXX no objeto de conexão, está chamando um método .fetchXXXX no objeto retornado pelo método .execute () da conexão.
Jack Bauer
1
Sim. Mas uma maneira de acabar com uma (aparentemente) cursor desnecessário com que a consulta a banco de dados: p
Jack Bauer
2
O uso explícito de cursores é um bom hábito, pois provavelmente haverá projetos futuros nos quais você trabalha onde as coisas não são confirmadas automaticamente.
Âmbar
1
Justo. Obrigado pela informação :)
Jack Bauer
36

De acordo com a documentação oficial, connection.execute()é um atalho não padrão que cria um objeto intermediário de cursor:

Connection.execute
Este é um atalho não padrão que cria um objeto de cursor chamando o método cursor (), chama o método execute () do cursor com os parâmetros fornecidos e retorna o cursor.

do utilizador
fonte
19

12.6.8 Usando sqlite3 eficiente ly

12.6.8.1 Usando métodos de atalho

Usando o fora do padrão execute() , executemany()e executescript()métodos do objeto Connection, o código pode ser escrito mais conciso ly, porque você não tem que criar o (muitas vezes supérfluos ) Cursor objetos explicitamente. Em vez disso, os objetos Cursor são criados implicitamente e esses métodos de atalho retornam os objetos do cursor. Dessa forma, você pode executar uma instrução SELECT e iterá-la diretamente usando apenas uma única chamada no objeto Connection.

( documentação do sqlite3 ; ênfase minha.)

Por que não usar apenas o objeto de conexão?

Como esses métodos do objeto de conexão não são padrão , ou seja, eles não fazem parte do Python Database API Specification v2.0 (PEP 249).

Desde que você use os métodos padrão do objeto Cursor, pode ter certeza de que, se mudar para outra implementação de banco de dados que segue a especificação acima, seu código será totalmente portátil. Talvez você só precise alterar a importlinha.

Mas se você usar, connection.executehá uma chance de que a troca não seja tão simples. Essa é a principal razão pela qual você pode querer usar cursor.execute.

No entanto, se você tiver certeza de que não vai mudar, eu diria que não há problema em connection.executeusar o atalho e ser "eficiente".

AXO
fonte
1

Isso nos permite ter vários ambientes de trabalho separados pela mesma conexão com o banco de dados.

Aluno do Python
fonte