Dlaczego musisz tworzyć kursor podczas wykonywania zapytań w bazie danych sqlite?

140

Jestem zupełnie nowy w module sqlite3 w Pythonie (i ogólnie w języku SQL), a to kompletnie mnie przytłacza. Obfity brak opisów cursorobiektów (a raczej ich konieczności) również wydaje się dziwny.

Ten fragment kodu jest preferowanym sposobem wykonywania czynności:

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

Ten nie jest, mimo że działa równie dobrze i bez (pozornie bez sensu) cursor:

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

Czy ktoś może mi powiedzieć, dlaczego potrzebuję cursor?
Po prostu wydaje się bezcelowe. Dla każdej metody w moim skrypcie, która uzyskuje dostęp do bazy danych, mam utworzyć i zniszczyć cursor?
Dlaczego po prostu nie użyć connectionobiektu?

Shaun Mitchell
źródło

Odpowiedzi:

63

Wydaje mi się, że to źle zastosowana abstrakcja. Kursor db to abstrakcja przeznaczona do przechodzenia przez zestaw danych.

Z artykułu Wikipedii na ten temat :

W informatyce i technologii kursor bazy danych jest strukturą kontrolną, która umożliwia przechodzenie po rekordach w bazie danych. Kursory ułatwiają późniejsze przetwarzanie w połączeniu z przechodzeniem, takie jak pobieranie, dodawanie i usuwanie rekordów bazy danych. Kursor bazy danych charakterystyczny dla przechodzenia sprawia, że ​​kursory są podobne do koncepcji iteratora w języku programowania.

I:

Kursorów można używać nie tylko do pobierania danych z DBMS do aplikacji, ale także do identyfikowania wiersza w tabeli, który ma zostać zaktualizowany lub usunięty. Standard SQL: 2003 definiuje w tym celu pozycjonowaną aktualizację i pozycjonowane instrukcje SQL usuwania. Takie instrukcje nie używają zwykłej klauzuli WHERE z predykatami. Zamiast tego kursor identyfikuje wiersz. Kursor musi być otwarty i już umieszczony w wierszu za pomocą instrukcji FETCH.

Jeśli sprawdzisz dokumentację w module Python sqlite , zobaczysz, że moduł Pythona cursorjest potrzebny nawet do CREATE TABLEinstrukcji, więc jest używany w przypadkach, gdy sam connectionobiekt powinien wystarczyć - jak poprawnie wskazał OP. Taka abstrakcja różni się od tego, co ludzie rozumieją jako kursor db, a tym samym dezorientacja / frustracja ze strony użytkowników. Niezależnie od wydajności, to tylko ogólne pojęcie. Byłoby miło, gdyby wskazano w dokumentacji, że moduł pythona cursorjest nieco inny niż kursor w SQL i bazach danych.

Basel Shishani
źródło
8
+1 za uznanie (na początku) bardzo mylącego rozróżnienia między "tradycyjnymi" kursorami db a kursorami używanymi dla db w Pythonie
Paul Draper
4
Właściwie można po prostu stworzyć tabelę, nawet bez użycia kursora .
Serge Stroobandt
Użycie kursora wydaje się zgodne z podaną przez ciebie definicją: „kursor bazy danych to struktura kontrolna, która umożliwia przechodzenie po rekordach w bazie danych”. Na przykład c.execute('''SELECT * FROM users''')zwraca iterator, który można wywołać fetchall()(lub inną metodę kursora). Niektóre zapytania SQL zwracają puste iteratory, ale nie należy się tego spodziewać.
Moce
40

Potrzebujesz obiektu kursora, aby pobrać wyniki. Twój przykład działa, ponieważ jest to an INSERTi dlatego nie próbujesz odzyskać z niego żadnych wierszy, ale jeśli spojrzysz na sqlite3dokumenty , zauważysz, że nie ma żadnych .fetchXXXXmetod na obiektach połączeń, więc jeśli spróbujesz to zrobić a SELECTbez kursora nie miałbyś możliwości uzyskania danych wynikowych.

Obiekty kursorów pozwalają na śledzenie, który zestaw wyników jest którym, ponieważ możliwe jest uruchomienie wielu zapytań, zanim zakończysz pobieranie wyników pierwszego.

Bursztyn
źródło
6
Warto też pamiętać: PEP 249 nie definiuje executeobiektu połączenia, jest to sqlite3rozszerzenie.
Cat Plus Plus
5
Nadal działa z instrukcjami SELECT: pastebin.com/5ZbhfEn7 . Powodem jest to, że nie wywołujesz żadnych metod .fetchXXXX w obiekcie połączenia, a wywołujesz metodę .fetchXXXX na obiekcie zwróconym przez metodę .execute () połączenia.
Shaun Mitchell,
1
Tak. Ale w jeden sposób kończysz z (pozornie) niepotrzebnym kursorem do przeszukiwania bazy danych: p
Shaun Mitchell,
3
Jawne używanie kursorów jest dobrym nawykiem, ponieważ prawdopodobnie będą w przyszłości projekty, nad którymi będziesz pracować, w których rzeczy nie będą automatycznie zatwierdzane.
Bursztynowy
1
Słusznie. Dzięki za informację :)
Shaun Mitchell
38

Zgodnie z oficjalną dokumentacją connection.execute() jest to niestandardowy skrót, który tworzy pośredni obiekt kursora:

Connection.execute
Jest to niestandardowy skrót, który tworzy obiekt kursora przez wywołanie metody kursor (), wywołuje metodę kursora execute () z podanymi parametrami i zwraca kursor.

użytkownik
źródło
24

12.6.8. Używanie sqlite3 sprawnego ly

12.6.8.1. Używanie skrótów metody

Korzystanie z niestandardowych execute() , executemany()a executescript()metody obiektu Connection, kod może być napisany bardziej zwięzły ly ponieważ nie trzeba, aby stworzyć (często zbędne ) Kursor obiekty wyraźnie. Zamiast tego obiekty Cursor są tworzone niejawnie, a te metody skrótów zwracają obiekty kursora. W ten sposób można wykonać instrukcję SELECT i iterować po niej bezpośrednio, używając tylko jednego wywołania obiektu Connection.

( dokumentacja sqlite3 ; wyróżnienie moje).

Dlaczego po prostu nie użyć obiektu połączenia?

Ponieważ te metody obiektu połączenia są niestandardowe , tj. Nie są częścią specyfikacji API bazy danych Python v2.0 (PEP 249).

Dopóki używasz standardowych metod obiektu Cursor, możesz być pewien, że jeśli przełączysz się na inną implementację bazy danych, która jest zgodna z powyższą specyfikacją, Twój kod będzie w pełni przenośny. Być może będziesz musiał tylko zmienić importlinię.

Ale jeśli użyjesz, connection.executeistnieje szansa, że ​​zmiana nie będzie taka prosta. To jest główny powód, dla którego możesz chcieć użyć cursor.executezamiast tego.

Jeśli jednak jesteś pewien, że nie zamierzasz się przełączać, powiedziałbym, że całkowicie w porządku jest skorzystać ze connection.executeskrótu i ​​być „wydajnym”.

AXO
źródło
3

Daje nam możliwość posiadania wielu oddzielnych środowisk roboczych za pośrednictwem tego samego połączenia z bazą danych.

Python Learner
źródło