Постављање упита¶
Да би могао да се постави упит, потребно је креирати објекат који се
назива курсор. То се ради тако што се над објектом конекције
позове метод cursor()
. На пример,
import sqlite3
db_conn = sqlite3.connect(...)
cur = db_conn.cursor()
...
db_conn.close()
Упит затим можемо да извршимо позивом методе execute
на креираном
курсору. Параметар је ниска која садржи текст упита на језику SQL. На
пример, унос новог ученика у табелу може да се изврши на следећи начин:
cur.execute("INSERT INTO ucenik (ime, prezime, razred, odeljenje)" +
"VALUES ('Петар', 'Петровић', 1, 1)");
Поделу упита на две ниске смо урадили само прегледности ради.
Уколико се ради о неком упиту који врши измене над базом (INSERT
,
UPDATE
, DELETE
), након извршавања упита (или неколико таквих
упита) потребно је над конекцијом позвати методу commit
којом се
измене трајно уписују у базу. Текст целокупног програма који уписује
новог ученика тада гласи овако.
import os
import sqlite3
db_conn = sqlite3.connect(os.path.join(os.getcwd(), 'dnevnik.db'))
cur = db_conn.cursor()
cur.execute("INSERT INTO ucenik (ime, prezime, razred, odeljenje)" +
"VALUES ('Петар', 'Петровић', 1, 1)");
db_conn.commit()
db_conn.close()
Ако се методом execute
извршава упит читања података из базе (упит
SELECT
), тада је повратна вредност позива методе execute
резултујућа табела, смештена у специјализованој структури података
коју можемо посматрати као листу врста, што значи да помоћу петље
for
можемо обрађивати једну по једну врсту. Свака врста је уређена
торка. Размотримо наредни програм који чита и исписује имена и
презимена свих ученика.
import os
import sqlite3
db_conn = sqlite3.connect(os.path.join(os.getcwd(), 'dnevnik.db'))
cur = db_conn.cursor()
res = cur.execute("SELECT ime, prezime FROM ucenik");
for row in res:
print(row[0], row[1])
db_conn.close()
Променљива res
садржи резултат упита, док променљива row
садржи редом једну по једну врсту тог резултата. Врсте су уређени
парови (двочлане торке) и име и презиме се издвајају из њих коришћењем
индексног приступа (row[0]
ће бити име, а row[1]
презиме). Читљивији код се може добити ако се петља реализује на следећи начин:
for ime, prezime in res:
print(ime, prezime)
Могуће је подесити и да врсте резултата упита буду речници (а не
уређене торке), тако да се подацима унутар врсте може приступити било
на основу редног броја, било на основу назива колоне. Након повезивања
са базом, отвореној конекцији је потребно променити атрибут
row_factory
, чији је параметар функција која трансформише сваку
врсту пре него што јој се приступи. Да би се торка трансформисала у
речник, довољно је вредност тог параметра поставити на функцију
sqlite3.Row
.
...
db_conn = sqlite3.connect(os.path.join(os.getcwd(), 'dnevnik.db'))
db_conn.row_factory = sqlite3.Row
cur = db_conn.cursor()
res = cur.execute("SELECT ime, prezime FROM ucenik");
for row in res:
print(row["ime"], row["prezime"])
db_conn.close()
Нагласимо још једном да је у реалним програмима у склопу упита
SELECT
увек пожељно експлицитно навести називе и редослед колона
које се читају из базе. Тај редослед се после користи и у петљама које
обрађују резултате упита, па ако се он упари са оним наведеним након
кључне речи SELECT
, тада нема опасности да скрипт престане да ради
ако се структура табела у бази мало промени (нпр. дода се нека нова
колона).
Резултат упита се чува у специјалној структури података кроз коју
можемо да итерирамо помоћу петље for
. Та структура података није
листа и сасвим је могуће да се врше разне оптимизације које доводе до
тога да се цела табела резултата никада не чува истовремено у
меморији.
Ако нам итерирање кроз редове резултата није довољно, већ желимо да се
кроз резултат крећемо слободније, листу торки у којој се чува цео
резултат можемо да добијемо коришћењем метода fetchall
над
курсором над којим је извршен упит. Слично, метод fetchone
враћа
наредну врсту у резултату претходно извршеног упита.