SQLite Pythonissa
Pythonin standardikirjaston osana on moduuli sqlite3
,
jonka kautta pystyy käsittelemään SQLite-tietokantaa.
Tämä sivu kertoo perusasiat moduulin käyttämisestä,
ja voit halutessasi etsiä lisätietoa Pythonin dokumentaatiosta.
Esimerkki
Seuraava koodi käyttää tietokantaa, joka on tiedostossa testi.db
.
Koodi luo taulun Tuotteet
ja lisää sinne viisi riviä.
Tämän jälkeen koodi hakee ja näyttää taulun rivit.
import sqlite3
db = sqlite3.connect("testi.db")
db.isolation_level = None
c = db.cursor()
c.execute("CREATE TABLE Tuotteet (id INTEGER PRIMARY KEY, nimi TEXT, hinta INTEGER)")
c.execute("INSERT INTO Tuotteet (nimi,hinta) VALUES ('retiisi',7)")
c.execute("INSERT INTO Tuotteet (nimi,hinta) VALUES ('porkkana',5)")
c.execute("INSERT INTO Tuotteet (nimi,hinta) VALUES ('nauris',4)")
c.execute("INSERT INTO Tuotteet (nimi,hinta) VALUES ('lanttu',8)")
c.execute("INSERT INTO Tuotteet (nimi,hinta) VALUES ('selleri',4)")
c.execute("SELECT * FROM Tuotteet")
print(c.fetchall())
Koodin tulostus on seuraava:
[(1, 'retiisi', 7), (2, 'porkkana', 5), (3, 'nauris', 4), (4, 'lanttu', 8), (5, 'selleri', 4)]
Tietokantaa käytetään kursorin kautta,
jonka metodi execute
suorittaa halutun komennon.
Komennon SELECT
suorituksen jälkeen metodi fetchall
hakee tulosrivit.
Asetus isolation_level = None
tarkoittaa, että oletuksena jokainen
komento on oma transaktionsa (kuten SQLite-tulkissa).
Huomaa, että jos suoritat koodin uudestaan,
tapahtuu virhe, koska taulu Tuotteet
on jo tietokannassa mutta
ohjelma yrittää luoda sen uudestaan.
Voit aina halutessasi nollata tietokannan sisällön
poistamalla tiedoston testi.db
.
Tiedon hakeminen käyttäjänä
Seuraava koodi näyttää esimerkin, jossa käyttäjä pystyy
hakemaan tietoa tietokannasta, jossa on valmiina taulu Tuotteet
:
import sqlite3
db = sqlite3.connect("testi.db")
db.isolation_level = None
c = db.cursor()
print("Anna tuotteen nimi:")
nimi = input()
c.execute("SELECT hinta FROM Tuotteet WHERE nimi=?",[nimi])
tiedot = c.fetchone()
if tiedot != None:
print("Hinta:",tiedot[0])
else:
print("Tuotetta ei löytynyt")
Tässä on käytössä parametrisoitu kysely,
jossa on käyttäjän antaman tiedon kohdalla ?
ja
tieto annetaan erikseen listassa kyselyn jälkeen.
Metodi fetchone
antaa yhden tulosrivin tai None
,
jos kysely ei palauttanut mitään riviä.
Tässä on esimerkkejä koodin toiminnasta:
Anna tuotteen nimi:
selleri
Hinta: 4
Anna tuotteen nimi:
banaani
Tuotetta ei löytynyt
Parametrisoitu kysely on turvallinen tapa yhdistää käyttäjän antamaa tietoa kyselyyn, koska tällöin käyttäjän antama tieto ei sekoitu SQL-komentoihin. Sen sijaan vaarallinen tapa olisi yhdistää käyttäjän antama tieto suoraan kyselyyn:
c.execute("SELECT hinta FROM Tuotteet WHERE nimi='"+nimi+"'")
Nyt käyttäjä voisi antaa vaikka seuraavan tuotteen “nimen”:
Anna tuotteen nimi:
' OR id=1 OR nimi='
Hinta: 7
Tämä tuottaa kyselyn SELECT hinta FROM Tuotteet WHERE nimi='' OR id=1 OR nimi=''
,
joka hakeekin tietokannasta tuotteen, jonka id on 1.
Käyttäjä voisi siis koettaa hakea tietoa, johon hänellä ei kuuluisi olla pääsyä.
Tällaisesta kyselyn rakennetta muuttavasta käyttäjän antamasta tiedosta käytetään nimeä SQL-injektio. Tämä oli etenkin takavuosina tavallinen tapa murtautua huonosti toteutettuihin nettisivustoihin.
Tiedon muuttaminen käyttäjänä
Tässä on vielä esimerkki, jossa käyttäjä pystyy lisäämään tuotteen:
import sqlite3
db = sqlite3.connect("testi.db")
db.isolation_level = None
c = db.cursor()
print("Anna tuotteen nimi:")
nimi = input()
print("Anna tuotteen hinta:")
hinta = input()
c.execute("INSERT INTO Tuotteet(nimi,hinta) VALUES (?,?)",[nimi,hinta])
print("Tuote lisätty id:llä",c.lastrowid)
Kuten tiedon hakemisessa, turvallinen tapa toteuttaa kysely on
käyttää parametrisoitua kyselyä.
Rivin lisäämisen jälkeen kentässä lastrowid
on
lisätyn rivin id-numero, josta olisi hyötyä,
jos esimerkiksi lisäisimme vielä toisen rivin,
joka viittaa siihen.
Koodin suoritus voi näyttää seuraavalta:
Anna tuotteen nimi:
banaani
Anna tuotteen hinta:
3
Tuote lisätty id:llä 6
Virheenkäsittely
Jos kyselyssä tapahtuu virhe, niin tämä keskeyttää ohjelman suorituksen.
Näin käy vaikkapa seuraavassa kyselyssä, jos taulua Kurssit
ei ole olemassa:
c.execute("SELECT * FROM Kurssit")
Tässä tapauksessa ohjelma päättyy seuraavaan virheeseen:
Traceback (most recent call last):
File "testi4.py", line 7, in <module>
c.execute("SELECT * FROM Kurssit")
sqlite3.OperationalError: no such table: Kurssit
Voimme kuitenkin halutessamme varautua virheeseen try
-rakenteen
avulla vaikkapa näin:
try:
c.execute("SELECT * FROM Kurssit")
except:
print("Kysely ei onnistunut")
Nyt virhetilanteessa ohjelma tulostaa viestin ja jatkaa toimintaansa.