sqlite3

Basis data SQL bawaan sqlite3 untuk create, insert, dan query berparameter.

Daftar isi

Modul sqlite3 menyertakan mesin basis data SQLite di dalam pustaka standar Python, sehingga basis data SQL dapat dibuat dan dikueri tanpa memasang server atau mengatur pengguna apa pun. Seluruh data tersimpan pada satu berkas, dan perintah SQL standar dipakai untuk membuat tabel, menyisipkan baris, serta membaca dan memperbarui datanya. Topik ini membahas siklus lengkap tersebut, dengan penekanan pada query berparameter yang menjaga keamanan data.

Membuat basis data dan tabel#

Fungsi sqlite3.connect() membuka berkas basis data pada jalur yang diberikan dan membuatnya otomatis apabila berkas itu belum ada. Setiap perintah SQL dijalankan melalui cursor, yaitu objek perantara yang diperoleh dari metode cursor() milik koneksi. Pernyataan CREATE TABLE menetapkan nama tabel, nama kolom, dan tipe datanya, sedangkan kolom INTEGER PRIMARY KEY diisi otomatis oleh SQLite sebagai nomor urut yang unik.

python buat-basis-data.py
import sqlite3

conn = sqlite3.connect("laboratorium.db")
cur = conn.cursor()
cur.execute("CREATE TABLE alat (id INTEGER PRIMARY KEY, nama TEXT, jumlah INTEGER)")
alat = [("mikroskop", 8), ("beker gelas", 24), ("termometer", 15)]
cur.executemany("INSERT INTO alat (nama, jumlah) VALUES (?, ?)", alat)
conn.commit()
cur.execute("SELECT COUNT(*) FROM alat")
print("jumlah baris:", cur.fetchone()[0])
conn.close()
text Keluaran
jumlah baris: 3

Metode executemany() menjalankan satu perintah INSERT untuk setiap tuple pada daftar, dan tanda ? pada perintah tersebut adalah tempat nilai yang dikirim secara terpisah. Kolom id tidak diberi nilai apa pun karena SQLite mengisinya secara otomatis dengan nomor yang naik untuk setiap baris baru. Panggilan conn.commit() menyimpan perubahan ke berkas secara permanen, sedangkan conn.close() menutup koneksi dan melepaskan berkasnya. Apabila program selesai tanpa commit(), seluruh penyisipan yang baru dilakukan hilang, karena transaksi yang belum disimpan tidak ditulis ke berkas.

Query berparameter#

Tanda ? pada perintah SQL adalah parameter placeholder, yaitu tempat kosong yang nilainya dikirim melalui tuple terpisah pada pemanggilan execute(). Pustaka mengurus pengutipan nilai tersebut, sehingga teks berisi tanda kutip maupun data dari luar program tetap aman disisipkan. Hasil SELECT dibaca dengan fetchall() yang mengembalikan list berisi tuple, atau fetchone() yang mengembalikan tuple pertama saja.

python Contoh: SELECT berparameter dan agregat
import sqlite3

conn = sqlite3.connect("laboratorium.db")
cur = conn.cursor()
cur.execute("SELECT nama, jumlah FROM alat WHERE jumlah >= ?", (10,))
for baris in cur.fetchall():
    print(baris)
cur.execute("SELECT COUNT(*), SUM(jumlah) FROM alat")
print(cur.fetchone())
conn.close()
text Keluaran
('beker gelas', 24)
('termometer', 15)
(3, 47)

Nilai 10 pada tuple bertindak sebagai batas bawah kolom jumlah, dan baris yang memenuhinya dikembalikan sebagai tuple bertipe sesuai definisi tabelnya. Perintah agregat seperti COUNT(*) dan SUM() menghitung seluruh baris tanpa perulangan Python sama sekali, dan hasilnya tiba sebagai satu tuple. Satu tanda ? menerima tepat satu nilai, sehingga jumlah nilai harus cocok dengan jumlah tanda ? pada perintahnya.

Memperbarui data dan membaca kolom dengan nama#

Pernyataan UPDATE mengubah nilai kolom pada baris yang memenuhi syarat WHERE, dan tanpa syarat tersebut seluruh baris ikut berubah. Blok with conn: mengurus transaksi secara otomatis, yaitu commit() ketika blok selesai dengan sukses dan pembatalan ketika error muncul di tengah blok. Sifat koneksi dapat diatur sebelum kueri, dan salah satu pengaturan yang paling berguna adalah row_factory = sqlite3.Row yang mengubah hasil tuple menjadi objek baris yang kolomnya dibaca berdasarkan nama.

python Contoh: UPDATE dan sqlite3.Row
import sqlite3

conn = sqlite3.connect("laboratorium.db")
conn.row_factory = sqlite3.Row
cur = conn.cursor()
with conn:
    cur.execute("UPDATE alat SET jumlah = ? WHERE nama = ?", (10, "mikroskop"))
cur.execute("SELECT nama, jumlah FROM alat ORDER BY nama")
for baris in cur.fetchall():
    print(baris["nama"], baris["jumlah"])
conn.close()
text Keluaran
beker gelas 24
mikroskop 10
termometer 15

Nilai mikroskop berubah dari 8 menjadi 10 karena pembaruan hanya menyentuh baris yang namanya cocok. Ekspresi baris["nama"] memperjelas maksud kode dibandingkan baris[0], terutama pada tabel dengan banyak kolom, dan klausa ORDER BY nama memastikan urutan keluarannya tetap sama di semua mesin. Penghapusan baris memakai pernyataan DELETE FROM alat WHERE ... dengan syarat yang ditulis cermat, dan prinsip syaratnya sama dengan UPDATE, yaitu kueri tanpa WHERE menyentuh seluruh baris tabel.

Kesalahan umum#

Kesalahan pertama adalah memanggil execute() tanpa commit() lalu menutup program dengan anggapan data sudah tersimpan. SQLite memperlakukan perubahan sebagai transaksi tertunda, dan penutupan koneksi tanpa penyimpanan membuangnya tanpa peringatan. Perbaikannya adalah memakai conn.commit() setelah setiap kelompok perubahan, atau membungkus perubahannya dengan with conn: sebagaimana contoh pada bagian sebelumnya.

Kesalahan kedua adalah jumlah nilai parameter yang tidak cocok dengan jumlah tanda ?. Error yang muncul menyebutkan jumlah yang dibutuhkan perintah dan jumlah yang dikirim, sehingga penyebabnya mudah dilacak.

python Contoh: jumlah parameter yang tidak cocok
import sqlite3

conn = sqlite3.connect("laboratorium.db")
cur = conn.cursor()
try:
    cur.execute("SELECT nama FROM alat WHERE jumlah >= ?", (10, 20))
except sqlite3.ProgrammingError as e:
    print(type(e).__name__)
conn.close()
text Keluaran
ProgrammingError

Kesalahan ketiga adalah menjalankan CREATE TABLE yang sama pada program yang berulang. SQLite menolaknya dengan error karena tabelnya sudah ada, dan perbaikan yang lazim adalah menulis CREATE TABLE IF NOT EXISTS pada skrip penyiapan. Kesalahan terakhir adalah membangun perintah SQL melalui f-string untuk menghindari tuple, yang justru mengembalikan masalah pengutipan dan celah injeksi yang dibahas pada bagian query berparameter.

Satu kebiasaan kerja yang melengkapi daftar ini adalah memperlakukan koneksi dan cursor sebagai pasangan yang tidak dibagikan antarbagian program. Cursor menyimpan posisi hasil kueri yang sedang berjalan, sehingga satu cursor yang dipakai bergantian oleh dua proses baca saling menggeser posisinya. Membuat cursor baru untuk setiap kelompok kueri menghindarkan program dari kebingungan semacam itu, sedangkan koneksi boleh dibuka sekali di awal dan ditutup di akhir program.

Ringkasan#

  • sqlite3.connect() membuka atau membuat satu berkas basis data SQLite, dan cursor menjalankan seluruh perintah SQL-nya.
  • Parameter ? mengirim nilai ke perintah SQL dengan aman, menggantikan penyambungan string sepenuhnya.
  • fetchall() dan fetchone() membaca hasil SELECT, sedangkan commit() dan with conn: mengurus penyimpanan perubahan ke berkas.
  • row_factory = sqlite3.Row membuat kolom hasil kueri dibaca berdasarkan namanya, dan CREATE TABLE IF NOT EXISTS menjaga skrip penyiapan tetap dapat diulang.

Referensi#