Досега базата беше „отсреща“
В уроци 1–9 пишехте SQL в приложението и в phpMyAdmin — човек пише заявка, човек чете резултата. В модул 4 програмата на C# се свързваше с базата през ADO.NET. Днес правим същото от Python в Colab, защото оттук нататък базата ще е част от програма с AI: в урок 23 моделът ще пише заявката, в урок 24 ще описва резултата ѝ, в урок 25 ще пазим вектори в нея.
Ползваме SQLite — същата база, която стои зад примерите в приложението. Тя е един файл на диска и идва вградена в Python: модулът sqlite3 не иска инсталация, сървър, потребител и парола.
Пет думи, които стигат
import sqlite3
vrazka = sqlite3.connect("uchilishte.db") # файлът се създава, ако го няма
cur = vrazka.cursor()
cur.execute("SELECT name, grade FROM students WHERE class_id = ?", (2,))
for ime, uspeh in cur.fetchall():
print(ime, uspeh)
cur.execute("INSERT INTO classes (id, name) VALUES (?, ?)", (4, "11Г"))
vrazka.commit() # без commit записът не остава
vrazka.close()connectотваря файла и връща връзка (connection).cursorе „показалецът“, през който пращаме заявки и четем резултата — кактоSqlCommandв C#.execute(sql, параметри)изпълнява една заявка. Всяка?в текста се запълва от кортежа отдясно, по ред.fetchallвръща всички редове като списък от кортежи;fetchone— само първия.commitпотвърждава промените. Забравите ли го,INSERTиUPDATEизчезват при затваряне.
Същото, което знаете от C#
| C# (ADO.NET, модул 4) | Python (sqlite3) | |
|---|---|---|
| връзка | new SqlConnection(niz) | sqlite3.connect("baza.db") |
| команда | new SqlCommand(sql, vrazka) | cur.execute(sql, parametri) |
| параметър | @ime + AddWithValue | ? + кортеж |
| четене | ExecuteReader + Read() | fetchall() → списък от кортежи |
| запис | ExecuteNonQuery() | execute + commit() |
| затваряне | using | with / close() |
Защо параметрите са задължителни
Изкушението е да сглобите заявката с f-низ. Изглежда еднакво и работи… докато някой не напише нещо неочаквано в полето.
tarseno = "Ива' OR '1'='1" # това е въвел „потребителят“
sql = f"SELECT name FROM students WHERE name = '{tarseno}'"
print(sql)
# SELECT name FROM students WHERE name = 'Ива' OR '1'='1' ← връща ВСИЧКИSQL инжекция (SQL injection)
Атака, при която потребителски текст се вмъква в заявката и променя смисъла ѝ — чете чужди данни, а при по-лоши права трие таблици.
С параметър текстът никога не се смесва с кода на заявката: базата получава отделно „шаблон с ?“ и отделно „стойност“, и стойността си остава просто низ, колкото и кавички да съдържа.
cur.execute("SELECT name FROM students WHERE name = ?", (tarseno,))
print(cur.fetchall()) # [] — няма ученик с такова странно имеСправката като таблица: pandas
Списък от кортежи е удобен за програмата, но не и за човека. pandas чете резултата от заявка направо в DataFrame — таблица с имена на колони, която Colab показва красиво и която умее да смята.
import pandas as pd
df = pd.read_sql("""
SELECT c.name AS klas, ROUND(AVG(m.mark), 2) AS sreden
FROM classes c
JOIN students s ON s.class_id = c.id
JOIN marks m ON m.student_id = s.id
GROUP BY c.id
ORDER BY sreden DESC
""", vrazka)
df # в Colab последният израз се показва като таблица
print(df.to_string(index=False)) # същото като чист текст
print(df["sreden"].mean()) # pandas смята върху колонитеread_sql(sql, vrazka)изпълнява заявката и връща DataFrame; параметри се подават сparams=(…).to_string()дава текст за печат,to_csv()— CSV, който в урок 24 ще подаваме на модела.- Кой смята — SQL или pandas? Групирането и
AVGса работа на базата; pandas е за последната обработка и показването.
А MySQL?
Училищната база от уроци 8–9 е MySQL/MariaDB. От Python към нея се отива със същите пет думи, само библиотеката е друга и параметърът се пише %s вместо ?:
!pip -q install mysql-connector-python
import mysql.connector
from google.colab import userdata
vrazka = mysql.connector.connect(
host="db.uchilishte.local", user="uchenik",
password=userdata.get("DB_PAROLA"), database="uchilishte")
cur = vrazka.cursor()
cur.execute("SELECT name FROM students WHERE class_id = %s", (2,))
print(cur.fetchall())Какво трябва да запомниш
sqlite3е вграден в Python; базата е един файл.- Редът е
connect → cursor → execute → fetchall, а при запис — иcommit. - Стойностите влизат в заявката само през
?и кортеж. f-низ със SQL е SQL инжекция, която чака да се случи. - Параметрите и правата от урок 8 са две отделни защити — ползват се заедно.
pd.read_sqlправи от справката DataFrame; смятането е в SQL, показването — в pandas.