17. SQLite va ma’lumotlar bazasi

Dasturlashda ma’lumotlarni fayllarda saqlash har doim ham yetarli emas.

Masalan, Softromeda uchun quyidagi ma’lumotlarni saqlash kerak bo‘lishi mumkin:

foydalanuvchilar
mahsulotlar
buyurtmalar
to‘lovlar
xabarlar
loyihalar

Ma’lumotlar soni ko‘payganda oddiy JSON yoki CSV fayllari bilan ishlash qiyinlashadi.

Bunday vaziyatlarda ma’lumotlar bazasi ishlatiladi.

Python'da kichik va o‘rta loyihalar uchun juda qulay ma’lumotlar bazalaridan biri — SQLite.

Bu bobda:

  • ma’lumotlar bazasi nima?
  • SQLite
  • ma’lumotlar bazasiga ulanish
  • jadval yaratish
  • INSERT
  • SELECT
  • UPDATE
  • DELETE
  • tranzaksiyalar

mavzularini o‘rganamiz.


Ma’lumotlar bazasi nima?

Ma’lumotlar bazasi — ma’lumotlarni tartibli ravishda saqlash, izlash, o‘zgartirish va o‘chirish uchun ishlatiladigan tizim.

Masalan, foydalanuvchilar jadvali:

id    ism      yosh    shahar
1     Ali      25      Toshkent
2     Vali     30      Samarqand
3     Sami     22      Buxoro

Bu yerda:

id
ism
yosh
shahar

ustunlar hisoblanadi.

Har bir foydalanuvchi esa alohida qator.


Ma’lumotlar bazasi bilan ishlash

Ma’lumotlar bazasida odatda quyidagi amallar bajariladi:

CREATE
INSERT
SELECT
UPDATE
DELETE

Ularning ma’nosi:

CREATE → yaratish
INSERT → qo‘shish
SELECT → o‘qish
UPDATE → o‘zgartirish
DELETE → o‘chirish

Bu amallar ko‘pincha SQL tili orqali bajariladi.


SQLite

SQLite — alohida server talab qilmaydigan ma’lumotlar bazasi.

Python'da SQLite bilan ishlash uchun alohida kutubxona o‘rnatish shart emas.

Python standart kutubxonasida:

sqlite3

moduli mavjud.

Uni:

import sqlite3

orqali ishlatamiz.


SQLite fayli

SQLite ma’lumotlar bazasini bitta faylda saqlashi mumkin.

Masalan:

softromeda.db

Bu fayl ichida jadvallar va ularning ma’lumotlari saqlanadi.


Ma’lumotlar bazasiga ulanish

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

print(
    "Ma'lumotlar bazasiga ulanish muvaffaqiyatli."
)

ulanish.close()

connect()

Quyidagi kod:

sqlite3.connect(
    "softromeda.db"
)

agar fayl mavjud bo‘lmasa, uni yaratadi.

Agar mavjud bo‘lsa, shu ma’lumotlar bazasiga ulanadi.


Ulanishni yopish

Ish tugagach ulanishni yopish kerak:

ulanish.close()

To‘liq ko‘rinish:

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

print(
    "Ulanish amalga oshirildi."
)

ulanish.close()

print(
    "Ulanish yopildi."
)

Kursor

SQL buyruqlarini bajarish uchun cursor kerak.

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

print(
    "Kursor yaratildi."
)

ulanish.close()

Kursor SQL buyruqlarini bajarish va natijalarni olish uchun ishlatiladi.


Jadval yaratish

Foydalanuvchilar jadvalini yaratamiz.

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

kursor.execute(
    """
    CREATE TABLE IF NOT EXISTS foydalanuvchilar (
        id INTEGER PRIMARY KEY,
        ism TEXT NOT NULL,
        yosh INTEGER,
        shahar TEXT
    )
    """
)

ulanish.commit()

ulanish.close()

Jadval ustunlari

Yuqoridagi jadval:

id
ism
yosh
shahar

ustunlaridan tashkil topgan.

id:

INTEGER PRIMARY KEY

sifatida belgilangan.

Bu foydalanuvchini yagona identifikatsiya qilishga yordam beradi.


TEXT

Matn saqlash uchun:

TEXT

ishlatiladi.

Masalan:

ism TEXT

INTEGER

Butun sonlar uchun:

INTEGER

ishlatiladi.

Masalan:

yosh INTEGER

NOT NULL

Agar qiymat majburiy bo‘lishi kerak bo‘lsa:

NOT NULL

ishlatiladi.

Masalan:

ism TEXT NOT NULL

Bu foydalanuvchining ismi bo‘sh bo‘lishiga yo‘l qo‘ymaydi.


INSERT

Jadvalga ma’lumot qo‘shish uchun INSERT ishlatiladi.

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

kursor.execute(
    """
    INSERT INTO foydalanuvchilar
    (ism, yosh, shahar)
    VALUES (?, ?, ?)
    """,
    (
        "Ali",
        25,
        "Toshkent"
    )
)

ulanish.commit()

ulanish.close()

Nima uchun ? ishlatiladi?

SQL so‘roviga qiymatlarni to‘g‘ridan-to‘g‘ri qo‘shish tavsiya etilmaydi.

Masalan, bunday yozish xavfli:

ism = "Ali"

kursor.execute(
    f"""
    INSERT INTO foydalanuvchilar
    (ism)
    VALUES ('{ism}')
    """
)

Buning o‘rniga parametrli so‘rov ishlatiladi:

kursor.execute(
    """
    INSERT INTO foydalanuvchilar
    (ism)
    VALUES (?)
    """,
    (ism,)
)

Bu SQL injection kabi muammolardan himoyalanishga yordam beradi.


Bir nechta ma’lumot qo‘shish

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

foydalanuvchilar = [
    ("Ali", 25, "Toshkent"),
    ("Vali", 30, "Samarqand"),
    ("Sami", 22, "Buxoro")
]

kursor.executemany(
    """
    INSERT INTO foydalanuvchilar
    (ism, yosh, shahar)
    VALUES (?, ?, ?)
    """,
    foydalanuvchilar
)

ulanish.commit()

ulanish.close()

executemany()

executemany() bir xil SQL buyruğini bir nechta ma’lumot bilan bajarishga yordam beradi.

Masalan:

kursor.executemany(
    """
    INSERT INTO foydalanuvchilar
    (ism, yosh, shahar)
    VALUES (?, ?, ?)
    """,
    foydalanuvchilar
)

SELECT

Ma’lumotlarni olish uchun:

SELECT

ishlatiladi.

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

kursor.execute(
    """
    SELECT * FROM foydalanuvchilar
    """
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

ulanish.close()

fetchall()

fetchall() barcha natijalarni qaytaradi.

Masalan:

foydalanuvchilar = kursor.fetchall()

Natija:

[
    (1, 'Ali', 25, 'Toshkent'),
    (2, 'Vali', 30, 'Samarqand'),
    (3, 'Sami', 22, 'Buxoro')
]

fetchone()

Faqat bitta natijani olish:

kursor.execute(
    """
    SELECT * FROM foydalanuvchilar
    """
)

foydalanuvchi = kursor.fetchone()

print(
    foydalanuvchi
)

fetchmany()

Bir nechta natijani olish:

kursor.execute(
    """
    SELECT * FROM foydalanuvchilar
    """
)

foydalanuvchilar = kursor.fetchmany(
    2
)

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

Faqat kerakli ustunlarni olish

Barcha ustunlarni:

SELECT *

orqali olish mumkin.

Lekin faqat kerakli ustunlarni olish yaxshiroq:

kursor.execute(
    """
    SELECT ism, shahar
    FROM foydalanuvchilar
    """
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        f"Ism: {foydalanuvchi[0]}, "
        f"Shahar: {foydalanuvchi[1]}"
    )

WHERE

Muayyan shartga mos ma’lumotlarni olish uchun WHERE ishlatiladi.

Masalan, 25 yoshdan katta foydalanuvchilar:

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    WHERE yosh > ?
    """,
    (25,)
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

Ism bo‘yicha qidirish

ism = "Ali"

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    WHERE ism = ?
    """,
    (ism,)
)

foydalanuvchi = kursor.fetchone()

print(
    foydalanuvchi
)

ORDER BY

Ma’lumotlarni tartiblash uchun ORDER BY ishlatiladi.

Yosh bo‘yicha o‘sish tartibida:

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    ORDER BY yosh ASC
    """
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

Kamayish tartibi

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    ORDER BY yosh DESC
    """
)

LIMIT

Natijalar sonini cheklash mumkin.

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    LIMIT 2
    """
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

UPDATE

Mavjud ma’lumotni o‘zgartirish uchun:

UPDATE

ishlatiladi.

Masalan, Ali yoshini o‘zgartirish:

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

kursor.execute(
    """
    UPDATE foydalanuvchilar
    SET yosh = ?
    WHERE ism = ?
    """,
    (
        26,
        "Ali"
    )
)

ulanish.commit()

ulanish.close()

Bir nechta ustunni o‘zgartirish

kursor.execute(
    """
    UPDATE foydalanuvchilar
    SET yosh = ?, shahar = ?
    WHERE ism = ?
    """,
    (
        26,
        "Toshkent",
        "Ali"
    )
)

DELETE

Ma’lumotni o‘chirish uchun:

DELETE

ishlatiladi.

kursor.execute(
    """
    DELETE FROM foydalanuvchilar
    WHERE ism = ?
    """,
    ("Ali",)
)

ulanish.commit()

DELETE bilan ehtiyot bo‘lish

Quyidagi so‘rov:

DELETE FROM foydalanuvchilar

jadvaldagi barcha ma’lumotlarni o‘chiradi.

Shuning uchun odatda WHERE shartidan foydalanish kerak:

DELETE FROM foydalanuvchilar
WHERE id = ?

commit()

Ma’lumotlarni o‘zgartiradigan SQL amallaridan keyin:

ulanish.commit()

ishlatiladi.

Masalan:

kursor.execute(
    """
    INSERT INTO foydalanuvchilar
    (ism, yosh)
    VALUES (?, ?)
    """,
    (
        "Sami",
        22
    )
)

ulanish.commit()

commit() bajarilmasa, o‘zgarishlar doimiy saqlanmasligi mumkin.


rollback()

Agar xatolik yuz bersa, o‘zgarishlarni bekor qilish mumkin.

ulanish.rollback()

Masalan:

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

try:

    kursor.execute(
        """
        INSERT INTO foydalanuvchilar
        (ism, yosh)
        VALUES (?, ?)
        """,
        (
            "Ali",
            25
        )
    )

    ulanish.commit()

except sqlite3.Error:

    ulanish.rollback()

    print(
        "Xatolik yuz berdi. "
        "O‘zgarishlar bekor qilindi."
    )

finally:

    ulanish.close()

Tranzaksiya

Tranzaksiya — bir nechta ma’lumotlar bazasi amalini bitta mantiqiy operatsiya sifatida bajarish.

Masalan, bank tizimida:

bir hisobdan pul ayirish
boshqa hisobga pul qo‘shish

ikkalasi ham muvaffaqiyatli bajarilishi kerak.

Agar birinchi amal bajarilib, ikkinchisi xato bersa, tizim noto‘g‘ri holatga kelishi mumkin.

Tranzaksiya bunday vaziyatlarda juda muhim.


Tranzaksiya misoli

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

try:

    kursor.execute(
        """
        UPDATE hisoblar
        SET balans = balans - ?
        WHERE id = ?
        """,
        (
            100,
            1
        )
    )

    kursor.execute(
        """
        UPDATE hisoblar
        SET balans = balans + ?
        WHERE id = ?
        """,
        (
            100,
            2
        )
    )

    ulanish.commit()

    print(
        "Tranzaksiya muvaffaqiyatli bajarildi."
    )

except sqlite3.Error:

    ulanish.rollback()

    print(
        "Tranzaksiya bekor qilindi."
    )

finally:

    ulanish.close()

with yordamida ulanish

SQLite ulanishini with orqali boshqarish ham mumkin.

import sqlite3

with sqlite3.connect(
    "softromeda.db"
) as ulanish:

    kursor = ulanish.cursor()

    kursor.execute(
        """
        INSERT INTO foydalanuvchilar
        (ism, yosh)
        VALUES (?, ?)
        """,
        (
            "Sami",
            22
        )
    )

Bu usul resurslarni boshqarishni osonlashtiradi.


row_factory

Oddiy fetchall() natijani tuple ko‘rinishida qaytaradi:

(1, 'Ali', 25, 'Toshkent')

Lekin ustun nomlari bilan ishlash qulayroq bo‘lishi mumkin.

Buning uchun:

sqlite3.Row

ishlatish mumkin.

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

ulanish.row_factory = sqlite3.Row

kursor = ulanish.cursor()

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    """
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        f"Ism: {foydalanuvchi['ism']}"
    )

    print(
        f"Yosh: {foydalanuvchi['yosh']}"
    )

ulanish.close()

Bu usul katta dasturlarda kodni ancha tushunarli qiladi.


COUNT

Jadvaldagi yozuvlar sonini hisoblash:

kursor.execute(
    """
    SELECT COUNT(*)
    FROM foydalanuvchilar
    """
)

natija = kursor.fetchone()

print(
    f"Foydalanuvchilar soni: {natija[0]}"
)

AVG

O‘rtacha yoshni hisoblash:

kursor.execute(
    """
    SELECT AVG(yosh)
    FROM foydalanuvchilar
    """
)

natija = kursor.fetchone()

print(
    f"O‘rtacha yosh: {natija[0]}"
)

MAX va MIN

Eng katta yosh:

kursor.execute(
    """
    SELECT MAX(yosh)
    FROM foydalanuvchilar
    """
)

eng_katta_yosh = kursor.fetchone()[0]

print(
    f"Eng katta yosh: {eng_katta_yosh}"
)

Eng kichik yosh:

kursor.execute(
    """
    SELECT MIN(yosh)
    FROM foydalanuvchilar
    """
)

eng_kichik_yosh = kursor.fetchone()[0]

print(
    f"Eng kichik yosh: {eng_kichik_yosh}"
)

LIKE

Matn bo‘yicha qisman qidirish uchun LIKE ishlatiladi.

Masalan, ism A harfi bilan boshlansa:

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    WHERE ism LIKE ?
    """,
    (
        "A%",
    )
)

foydalanuvchilar = kursor.fetchall()

for foydalanuvchi in foydalanuvchilar:

    print(
        foydalanuvchi
    )

Bu yerda:

% → istalgan miqdordagi belgilar

ni bildiradi.


Jadval mavjudligini tekshirish

SQLite'da jadvallar haqida ma’lumot olish mumkin:

kursor.execute(
    """
    SELECT name
    FROM sqlite_master
    WHERE type = 'table'
    """
)

jadvallar = kursor.fetchall()

for jadval in jadvallar:

    print(
        f"Jadval: {jadval[0]}"
    )

Amaliy loyiha — Softromeda foydalanuvchilar bazasi

Endi kichik foydalanuvchilar boshqaruv tizimini yaratamiz.

Dastur:

ma’lumotlar bazasini yaratadi
foydalanuvchilar jadvalini yaratadi
foydalanuvchilar qo‘shadi
foydalanuvchilarni ko‘rsatadi
foydalanuvchini qidiradi
import sqlite3


ulanish = sqlite3.connect(
    "softromeda.db"
)

ulanish.row_factory = sqlite3.Row

kursor = ulanish.cursor()


kursor.execute(
    """
    CREATE TABLE IF NOT EXISTS foydalanuvchilar (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        ism TEXT NOT NULL,
        yosh INTEGER NOT NULL,
        shahar TEXT NOT NULL
    )
    """
)


foydalanuvchilar = [
    (
        "Ali",
        25,
        "Toshkent"
    ),
    (
        "Vali",
        30,
        "Samarqand"
    ),
    (
        "Sami",
        22,
        "Buxoro"
    )
]


kursor.executemany(
    """
    INSERT INTO foydalanuvchilar
    (ism, yosh, shahar)
    VALUES (?, ?, ?)
    """,
    foydalanuvchilar
)


ulanish.commit()


kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    ORDER BY id
    """
)

barcha_foydalanuvchilar = (
    kursor.fetchall()
)


print(
    "=== Softromeda foydalanuvchilari ==="
)

for foydalanuvchi in barcha_foydalanuvchilar:

    print(
        f"ID: {foydalanuvchi['id']}"
    )

    print(
        f"Ism: {foydalanuvchi['ism']}"
    )

    print(
        f"Yosh: {foydalanuvchi['yosh']}"
    )

    print(
        f"Shahar: {foydalanuvchi['shahar']}"
    )

    print(
        "--------------------"
    )


qidirilayotgan_ism = "Ali"

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    WHERE ism = ?
    """,
    (
        qidirilayotgan_ism,
    )
)

foydalanuvchi = kursor.fetchone()


if foydalanuvchi:

    print(
        f"Topildi: "
        f"{foydalanuvchi['ism']}"
    )

else:

    print(
        "Foydalanuvchi topilmadi."
    )


ulanish.close()

Ma’lumotlar bazasi bilan ishlashning umumiy sxemasi

Python'da SQLite bilan ishlashda ko‘pincha quyidagi tartibdan foydalanamiz:

1. sqlite3 import qilish
2. ma’lumotlar bazasiga ulanish
3. cursor yaratish
4. SQL buyruqlarini bajarish
5. natijani olish
6. commit qilish
7. ulanishni yopish

Masalan:

import sqlite3

ulanish = sqlite3.connect(
    "softromeda.db"
)

kursor = ulanish.cursor()

kursor.execute(
    """
    SELECT *
    FROM foydalanuvchilar
    """
)

natijalar = kursor.fetchall()

for natija in natijalar:

    print(
        natija
    )

ulanish.close()

SQL buyruqlarining asosiy guruhlari

Ma’lumotlar bazasida eng ko‘p uchraydigan buyruqlar:

CREATE
    jadval yaratish

INSERT
    ma’lumot qo‘shish

SELECT
    ma’lumot olish

UPDATE
    ma’lumot o‘zgartirish

DELETE
    ma’lumot o‘chirish

Amaliy mashqlar

Mashq 1

softromeda.db ma’lumotlar bazasini yarating.

Mashq 2

mahsulotlar jadvalini yarating.

U quyidagi ustunlarga ega bo‘lsin:

id
nom
narx
miqdor

Mashq 3

Jadvalga 5 ta mahsulot qo‘shing.

Mashq 4

Barcha mahsulotlarni SELECT yordamida oling.

Mashq 5

Narxi 100 dan katta mahsulotlarni toping.

Mashq 6

Mahsulotlardan birining narxini UPDATE yordamida o‘zgartiring.

Mashq 7

Bir mahsulotni DELETE yordamida o‘chiring.

Mashq 8

Mahsulotlarning umumiy sonini COUNT() yordamida toping.

Mashq 9

Mahsulotlarning o‘rtacha narxini AVG() yordamida hisoblang.

Mashq 10

Softromeda uchun mahsulot boshqaruv tizimini yarating.

Dastur:

ma’lumotlar bazasini yaratsin
mahsulot qo‘shsin
mahsulotlarni ko‘rsatsin
mahsulot qidirsin
mahsulot narxini o‘zgartirsin
mahsulotni o‘chirsin

Bob xulosasi

Bu bobda SQLite bilan ishlashni o‘rgandik.

Asosiy modul:

import sqlite3

Asosiy amallar:

sqlite3.connect()
cursor()
execute()
executemany()
fetchone()
fetchmany()
fetchall()
commit()
rollback()
close()

Asosiy SQL buyruqlari:

CREATE
INSERT
SELECT
UPDATE
DELETE

Muhim tushunchalar:

ma’lumotlar bazasi
jadval
ustun
qator
primary key
SQL
kursor
tranzaksiya
commit
rollback

SQLite kichik va o‘rta Python loyihalari uchun juda qulay. U alohida server talab qilmaydi va butun ma’lumotlar bazasini bitta faylda saqlashi mumkin.

Keyingi bobda 18. API va HTTP bilan ishlash mavzusini o‘rganamiz.