Ачааллж байна...
Өмнөх хичээлийн туршилтад та ийм мөрүүд харсан:
sql
CREATE TABLE IF NOT EXISTS notes (...)
INSERT INTO notes (text, done) VALUES (?, ?)
SELECT * FROM notesЭдгээр нь SQL — өгөгдлийн сангийн хэл. Энэ хичээл бүхэлдээ түүнд зориулагдана.
Гэхдээ эхлээд хүрээгээ тодорхой болгоё, учир нь энэ нь чухал.
Бид SQL бичиж сурахгүй. Дараагийн бүлгээс эхлэн SQLModel таны өмнөөс бүх SQL-ыг бичнэ. Та Python код бичих бөгөөд SQL нь дэлгэцийн ард үүснэ.
Тэгвэл яагаад SQL судалж байна вэ? Гурван шалтгаанаар.
Нэгд, алдааны мессежид SQL гардаг. Ямар нэг зүйл буруу болоход терминал дээр ийм зүйл харагдана:
sqlalchemy.exc.OperationalError: no such column: notes.priortyЭсвэл бүр бүтэн SQL мөр гарч ирнэ. Хэрэв та SQL-ыг огт таньдаггүй бол энэ мессеж айдас төрүүлнэ. Хэрэв танина бол — "аа, priorty гэж бичсэн байна, priority байх ёстой" гэж шууд ойлгоно.
Хоёрт, юу болж байгааг ойлгоход тусална. SQLModel-ийн код нь ид шид мэт харагддаг: session.add(note) гэж бичихэд ном хаа нэгтээ хадгалагдана. Хэрэв та тэр мөр нь INSERT INTO note ... гэсэн SQL болж хувирдгийг мэдэж байвал — ид шид биш, ойлгомжтой механизм болно.
Гуравт, айдас арилна. SQL нь эхлэгчдэд аймшигтай харагддаг: том үсгээр бичсэн, ер бусын синтакстай. Гэтэл үнэндээ энэ нь бараг англи хэл юм. Нэг удаа хараад ойлговол айдас алга болно.
Тиймээс зорилго нь: таних, ойлгох. Цээжлэх шаардлагагүй. Бичиж сурах шаардлагагүй. Зөвхөн харахад "энэ юу гэж байна" гэдгийг ойлгож чаддаг байх.
SQL гэдэг нь Structured Query Language — "бүтэцтэй асуултын хэл". Өгөгдлийн санд юу хийхийг хэлдэг хэл.
Түүний хамгийн гайхалтай онцлог нь: бараг англи хэлээр бичигдсэн. Жишээ нь:
sql
SELECT text FROM notes WHERE done = 0Үг үгээр орчуулбал: "Сонго text-ыг эндээс notes хаана done = 0". Өөрөөр хэлбэл: "notes хүснэгтээс, done нь 0 байгаа мөрүүдийн text баганыг өгөөч."
Энэ бол зориудаар хийгдсэн. SQL-ыг 1970-аад онд зохиохдоо программист бус хүмүүс ч уншиж чаддаг байхаар зорьсон. Тэр зорилго бүрэн биелээгүй ч (нарийн SQL нь маш төвөгтэй болдог) үндсэн тушаалууд нь одоо ч уншихад амархан хэвээр байна.
Том үсгийн тухай. SQL-ын түлхүүр үгсийг (SELECT, FROM, WHERE) уламжлалт байдлаар ТОМ үсгээр бичдэг. Энэ нь заавал биш — select гэж бичсэн ч ажиллана. Гэхдээ том үсэг нь түлхүүр үгийг таны өгөгдлийн нэрээс (хүснэгт, багана) ялгаж харуулдаг тул уншихад тустай. Бид тэр уламжлалыг дагана.
Одоо хамгийн чухал холбоо. SQL-д дөрвөн үндсэн тушаал байдаг бөгөөд тэдгээр нь та аль хэдийн мэддэг CRUD-тай яг таарна.
CRUD | HTTP method | SQL |
|---|---|---|
Create | POST |
|
Read | GET |
|
Update | PUT |
|
Delete | DELETE |
|
Дөрвөн эгнээ, гурван багана, гурвуулаа ижил зүйлийг өөр хэлээр илэрхийлж байна.
Энэ нь санамсаргүй биш. CRUD бол өгөгдөлтэй хийж болох үндсэн дөрвөн үйлдэл юм. HTTP түүнийг вэбийн хэлээр илэрхийлдэг; SQL түүнийг өгөгдлийн сангийн хэлээр илэрхийлдэг.
Тиймээс таны API-ийн endpoint бүр эцсийн дүндээ SQL болж хувирна:
POST /notes -> INSERT INTO note ...
GET /notes -> SELECT * FROM note
PUT /notes/1 -> UPDATE note SET ... WHERE id = 1
DELETE /notes/1 -> DELETE FROM note WHERE id = 1Бүлэг 12-т та үүнийг бодитоор харна.
Хамгийн түгээмэл, хамгийн чухал тушаал. Өгөгдөл авах.
Хамгийн энгийн хэлбэр
sql
SELECT * FROM notes"notes хүснэгтээс бүгдийг сонго."
* од нь "бүх багана" гэсэн үг. FROM notes нь аль хүснэгтээс гэдгийг заана.
Үр дүн: хүснэгтийн бүх мөр, бүх багана.
id | text | priority | done
---|-------------------|-----------|------
1 | Сүү авах | чухал | 0
2 | Номоо буцаах | энгийн | 1
3 | Тайлан бичих | яаралтай | 0Тодорхой багана
sql
SELECT text, done FROM notes"notes хүснэгтээс text болон done баганыг сонго."
Үр дүн: бүх мөр, гэхдээ зөвхөн хоёр багана.
text | done
------------------|------
Сүү авах | 0
Номоо буцаах | 1
Тайлан бичих | 0Танил санагдаж байна уу? Энэ бол Бүлэг 6-ын response_model хийдэг зүйлтэй ижил санаа — зөвхөн хэрэгтэй талбарыг сонгох.
WHERE — шүүх
sql
SELECT * FROM notes WHERE done = 0"notes хүснэгтээс, done нь 0 байгаа мөрүүдийг сонго."
WHERE бол нөхцөл. Түүний дараах хэсэг нь аль мөрүүдийг авахыг тодорхойлно.
Үр дүн:
id | text | priority | done
---|-------------------|-----------|------
1 | Сүү авах | чухал | 0
3 | Тайлан бичих | яаралтай | 0WHERE бол Python-ы if шиг. Таны API-д ийм код байсныг санаж байна уу?
python
result = [n for n in notes if not n["done"]]WHERE done = 0 нь яг тэр зүйлийг хийж байна — зөвхөн өгөгдлийн сангийн дотор, илүү хурдан.
Олон нөхцөл
sql
SELECT * FROM notes WHERE done = 0 AND priority = 'чухал'"done нь 0 БА priority нь 'чухал' байгаа мөрүүд."
AND (ба), OR (эсвэл) — Python-той ижил утгатай.
Текст утгыг ганц хашилтад бичдэгийг анзаараарай: 'чухал'. SQL-д текст ганц хашилттай, тоо хашилтгүй.
Тодорхой мөр
sql
SELECT * FROM notes WHERE id = 2"id нь 2 байгаа мөрийг сонго."
Энэ бол таны GET /notes/2 endpoint-ийн SQL хувилбар. find_note(2) функц эцсийн дүндээ ийм зүйл болно.
Хязгаарлах
sql
SELECT * FROM notes LIMIT 10"Эхний 10 мөрийг сонго."
sql
SELECT * FROM notes LIMIT 10 OFFSET 20"20 мөр алгасаад, дараагийн 10-ыг сонго."
Танил санагдаж байна уу? LIMIT болон OFFSET нь таны limit болон skip query parameter-тэй яг тэнцүү. Бүлэг 8-ын list_params dependency-д тэдгээрийг бэлдэж байсан; Бүлэг 13-т бид тэдгээрийг өгөгдлийн санд шууд дамжуулна.
Одоо та Python-ы slicing (result[skip : skip + limit]) болон SQL-ын LIMIT/OFFSET хоёрын ялгааг ойлгож болно. Python-ынх нь бүх өгөгдлийг авчраад дараа нь тасалдаг. SQL-ынх нь өгөгдлийн санд зөвхөн хэрэгтэйг нь асуудаг. Сая мөртэй хүснэгтэд энэ ялгаа бол бүх зүйл.
Эрэмбэлэх
sql
SELECT * FROM notes ORDER BY id DESC"id-гээр буурахаар эрэмбэлж сонго."
ORDER BY — эрэмбэлэх багана. DESC — буурах (descending). ASC — өсөх (ascending, default).
Таны sorted(result, key=lambda n: n["id"], reverse=True) кодтой ижил утгатай.
Тоолох
sql
SELECT COUNT(*) FROM notes"notes хүснэгтэд хэдэн мөр байгааг тоол."
Үр дүн: ганц тоо, жишээ нь 3.
Python-ы len(notes)-тэй ижил. Гэхдээ ялгаа нь чухал: len(notes) нь бүх мөрийг санах ойд авчрахыг шаарддаг; COUNT(*) нь өгөгдлийн санд тоолж, зөвхөн тоог буцаана. Сая мөртэй бол ялгаа асар их.
Шинэ мөр нэмэх.
sql
INSERT INTO notes (text, priority, done) VALUES ('Хурал бэлдэх', 'чухал', 0)"notes хүснэгтэд, text/priority/done баганад, эдгээр утгуудыг оруул."
Бүтэц нь тодорхой: эхлээд ямар багана, дараа нь ямар утга. Хоёрын дараалал таарах ёстой — эхний багана эхний утгыг авна.
id-г заагаагүйг анзаараарай. PRIMARY KEY багана нь автоматаар нэмэгддэг тул SQLite өөрөө дараагийн дугаарыг өгнө. Таны next_id тоолуур энэ ажлыг гараар хийж байсан; өгөгдлийн сан түүнийг үнэгүй өгч байна.
Энэ бол таны POST /notes endpoint-ийн SQL хувилбар.
Байгаа мөрийг өөрчлөх.
sql
UPDATE notes SET done = 1 WHERE id = 1"notes хүснэгтэд, done-ыг 1 болго, хаана id = 1."
Гурван хэсэг: UPDATE (аль хүснэгт), SET (юуг юу болгох), WHERE (аль мөрд).
Олон багана зэрэг:
sql
UPDATE notes SET text = 'Шинэ текст', done = 1 WHERE id = 1Таслалаар тусгаарлана.
WHERE-гүй UPDATE — маш аюултай
Энд чухал анхааруулга байна.
sql
UPDATE notes SET done = 1WHERE байхгүй. Энэ нь юу хийх вэ? Хүснэгтийн БҮХ мөрийг өөрчилнө. Мянган тэмдэглэл байсан бол мянгуулаа done = 1 болно.
Алдаа гарахгүй. Анхааруулга гарахгүй. Зүгээр л бүх өгөгдөл өөрчлөгдөнө, буцаах боломжгүй.
Энэ бол өгөгдлийн сантай ажиллаж байсан хүн бүрийн айдас юм. WHERE мартах нь маш түгээмэл, маш үнэтэй алдаа.
Сайн мэдээ: SQLModel-той ажиллахад та энэ эрсдэлээс хол байна. Учир нь SQLModel-д та объект дээр ажилладаг: тодорхой нэг тэмдэглэлийг олж, түүнийг өөрчилж, хадгалдаг. "Бүх мөрийг санамсаргүй өөрчлөх" гэсэн зүйл байхгүй.
Гэхдээ энэ эрсдэлийг мэдэж байх нь чухал — учир нь та хожим түүхий SQL бичих шаардлага гарч болно, эсвэл өөр хүний бичсэн SQL уншиж болно.
Мөр устгах.
sql
DELETE FROM notes WHERE id = 2"notes хүснэгтээс, id = 2 байгаа мөрийг устга."
Таны DELETE /notes/2 endpoint-ийн SQL хувилбар.
Дахин: WHERE-гүй бол аюултай
sql
DELETE FROM notesХүснэгтийн бүх мөрийг устгана. Бүх өгөгдөл алга. Буцаах боломжгүй.
UPDATE-тэй ижил анхааруулга, бүр илүү ноцтой. UPDATE-д өгөгдөл өөрчлөгддөг; DELETE-д огт алга болдог.
Дахин хэлэхэд: SQLModel-той ажиллахад та объект устгадаг тул энэ эрсдэл бага. Гэхдээ мэдэж байх нь зүйтэй.
Сүүлийн тушаал. Өмнөх хичээлд харсан:
sql
CREATE TABLE notes (
id INTEGER PRIMARY KEY,
text TEXT NOT NULL,
priority TEXT DEFAULT 'энгийн',
done INTEGER DEFAULT 0
)Мөр мөрөөр нь уншъя.
CREATE TABLE notes ( — "notes гэсэн хүснэгт үүсгэ, доор нь баганууд".
id INTEGER PRIMARY KEY — id нэртэй багана, төрөл нь бүхэл тоо, үндсэн түлхүүр. Үндсэн түлхүүр гэдэг нь: давтагдашгүй, мөр бүрийг ялгах утга. SQLite-д INTEGER PRIMARY KEY нь автоматаар нэмэгддэг.
text TEXT NOT NULL — text нэртэй багана, төрөл нь текст, хоосон байж болохгүй.
priority TEXT DEFAULT 'энгийн' — текст багана, утга өгөөгүй бол 'энгийн'.
done INTEGER DEFAULT 0 — бүхэл тоо, default 0.
Pydantic model-той харьцуулъя:
python
class Note(BaseModel):
id: int
text: str
priority: str = "энгийн"
done: bool = FalseМөр мөрөөр нь таарч байна. id: int -> id INTEGER. text: str (default байхгүй, заавал) -> text TEXT NOT NULL. priority: str = "энгийн" -> priority TEXT DEFAULT 'энгийн'.
Хоёулаа schema зарлаж байна — талбарын нэр, төрөл, заавал эсэх, default. Зөвхөн хэл нь өөр.
Бүлэг 11-т SQLModel нь энэ хоёрыг нэгтгэнэ: та Python class нэг удаа бичихэд тэр нь Pydantic model ч мөн, өгөгдлийн сангийн хүснэгт ч мөн болно. SQL-ыг та бичихгүй — SQLModel таны class-аас автоматаар үүсгэнэ.
Богино тэмдэглэл. SQLite-д цөөн төрөл байдаг:
SQLite | Python | Тайлбар |
|---|---|---|
|
| Бүхэл тоо |
|
| Бутархай тоо |
|
| Текст |
|
| Binary өгөгдөл |
Анзаараарай: BOOLEAN байхгүй. SQLite-д үнэн/худал утгыг INTEGER болгон хадгалдаг: 0 бол худал, 1 бол үнэн. Тиймээс дээрх жишээнүүдэд done = 0 гэж бичсэн, done = False биш.
Энэ нь SQLModel-той ажиллахад асуудал биш — SQLModel хөрвүүлэлтийг таны өмнөөс хийнэ. Та Python-д done: bool гэж бичихэд SQLModel түүнийг 0/1 болгож хадгалж, буцаан уншихдаа True/False болгоно. Гэхдээ .db файлыг шууд харвал 0 болон 1 харагдана — тэр нь яагаад гэдгийг мэдэж байх нь зүйтэй.
Шударга байя. SQL нь энэ хичээлд үзсэнээс хамаагүй том хэл юм. Бид дараах зүйлсийг үзэхгүй:
JOIN — хоёр хүснэгтийг нийлүүлэх. Жишээ нь тэмдэглэл болон эзэмшигчийг хамт авах. Энэ бол SQL-ын хамгийн хүчирхэг чадвар бөгөөд өөрөө том сэдэв.
GROUP BY, aggregate функцууд — өгөгдлийг бүлэглэж дүгнэх (жишээ нь priority бүрд хэдэн тэмдэглэл байгааг тоолох).
Subquery, index үүсгэх, view, trigger — илүү ахисан ойлголтууд.
Эдгээр нь бүгд ашигтай бөгөөд та хожим сурч болно. Гэхдээ энэ курсын хүрээнд SQLModel эдгээрийн ихэнхийг таны өмнөөс зохицуулна. Бүлэг 15-т бид "цаашдын зам"-д SQL-ыг гүнзгий сурахыг нэг чиглэл болгон нэрлэнэ.
Одоо энэ мэдлэгээ бодит ашигт хөрвүүлье. Хожим ийм алдаа гарвал:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: note.priorty
[SQL: SELECT note.id, note.text, note.priorty, note.done FROM note WHERE note.priorty = ?]Энэ нь эхлээд аймшигтай харагдана. Гэхдээ одоо та уншиж чадна.
no such column: note.priorty — "тийм багана байхгүй". Багааны нэр priorty — үсэг дутуу байна, priority байх ёстой.
[SQL: SELECT ... FROM note WHERE note.priorty = ?] — SQLModel-ийн үүсгэсэн SQL. Тэнд priorty гэж бичигдсэн байна.
Тэгэхээр таны Python кодод хаа нэгтээ priorty гэсэн үсгийн алдаа байна. Хайж, засна.
Хэрэв SQL таньдаггүй байсан бол энэ мессеж утгагүй тэмдэгтүүд байх байсан. Одоо энэ нь тодорхой заавар болж байна.
Өөр нэг түгээмэл:
sqlite3.IntegrityError: NOT NULL constraint failed: note.textNOT NULL constraint failed — "хоосон байж болохгүй гэсэн дүрэм зөрчигдлөө". note.text — аль баганад. Тэгэхээр та text талбаргүй тэмдэглэл хадгалахыг оролдсон байна.
Дахин: SQL-ыг таньдаг хүнд энэ нь ойлгомжтой.
Хүсвэл өмнөх хичээлийн test_db.py-г ашиглан SQL туршиж үзээрэй. Жишээ нь:
python
# test_db.py
import sqlite3
connection = sqlite3.connect("test.db")
cursor = connection.cursor()
cursor.execute("SELECT * FROM notes WHERE done = 0")
for row in cursor.fetchall():
print(row)
connection.close()WHERE нөхцөлийг өөрчилж, ORDER BY, LIMIT нэмж үзээрэй. SQL бодитоор ажиллахыг харах нь ойлголтыг бататгана.
Сонирхвол COUNT(*) туршиж үзээрэй:
python
cursor.execute("SELECT COUNT(*) FROM notes")
print(cursor.fetchone())fetchone() нь ганц мөр авдаг (fetchall() бүгдийг авдаг). Үр дүн нь (4,) гэх мэт нэг элементтэй tuple байна.
Анхаар: DELETE FROM notes эсвэл UPDATE notes SET ... гэсэн WHERE-гүй тушаалыг бүү турш — эсвэл зөвхөн туршилтын test.db дээр л турш. Тэдгээрийн үр дагаврыг мэдэрч болно, гэхдээ хэзээ ч бодит өгөгдөл дээр биш.
Зорилго нь SQL бичих биш, уншиж таних — SQLModel бичих ажлыг хийнэ.
SQL нь бараг англи хэлээр уншигдана: SELECT text FROM notes WHERE done = 0.
Түлхүүр үгсийг ТОМ үсгээр бичих нь уламжлал, заавал биш.
Дөрвөн тушаал = CRUD: INSERT (Create), SELECT (Read), UPDATE (Update), DELETE (Delete).
SELECT * FROM хүснэгт — бүгдийг. WHERE — шүүх (Python-ы if шиг). LIMIT/OFFSET — таны limit/skip. ORDER BY — эрэмбэлэх. COUNT(*) — тоолох.
WHERE-гүй UPDATE эсвэл DELETE нь бүх мөрд нөлөөлнө — анхааруулгагүй, буцаах боломжгүй.
CREATE TABLE нь schema зарлана — Pydantic model-той мөр мөрөөр таарна.
SQLite-д BOOLEAN байхгүй — 0/1 ашиглана. SQLModel хөрвүүлэлтийг хийнэ.
LIMIT нь Python-ы slicing-ээс үндсэн ялгаатай: өгөгдлийн санд зөвхөн хэрэгтэйг асуудаг, бүгдийг авчирдаггүй.
Практик ашиг: алдааны мессеж уншиж чадна — no such column, NOT NULL constraint failed гэх мэт.
Бүлэг 10 дууслаа. Та одоо өгөгдлийн сан яагаад хэрэгтэй (Хичээл 1), SQLite гэж юу болох (Хичээл 2), SQL хэрхэн уншихыг (Хичээл 3) мэднэ. Онолын суурь бэлэн.
Дараагийн бүлэгт бид гараа ажиллуулна. SQLModel — FastAPI-ийн зохиогчийн бүтээсэн сан — нь Python class-ыг өгөгдлийн сангийн хүснэгт болгож хувиргана. Та class Note(SQLModel, table=True) гэж бичихэд тэр нь Pydantic model ч мөн, хүснэгт ч мөн болно. Type hint гурав дахь удаагаа ажиллана: editor-т тусалж, API-д validation хийж, одоо өгөгдлийн сангийн schema болно. Бид хүснэгт үүсгэж, .db файл гарч ирэхийг харж, мөр нэмж, унших, засах, устгах бүх ажлыг Python объектоор хийнэ — ганц ч мөр SQL бичихгүйгээр.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.