Ачааллж байна...
Өмнөх хоёр бүлэгт бид зөвхөн уншиж байсан. SELECT өгөгдлийг хэзээ ч өөрчилдөггүй тул бид хүссэнээрээ туршиж, алдаж байсан бөгөөд хүснэгтүүд маань Бүлэг 1-д үүсгэсэн байдлаараа хэвээр үлдсэн. Энэ бүлгээс эхлэн нөхцөл байдал өөрчлөгдөнө. Бид өгөгдлийг өөрчилдөг гурван тушаалыг сурна: INSERT нь шинэ мөр нэмдэг, UPDATE нь байгаа мөрийг засдаг, DELETE нь мөрийг устгадаг. Энэ гурав нийлээд SELECT-тэй хамт өгөгдлийн сантай ажиллах бүх үндсэн үйлдлийг бүрдүүлдэг.
Энэ хичээлд INSERT-ээр эхэлнэ. Гурвын дотроос INSERT нь хамгийн аюулгүй нь, учир нь шинэ мөр нэмэх нь байгаа өгөгдлийг эвдэхгүй. Гэхдээ энд ч гэсэн нэг чухал дадал бий — баганын жагсаалтыг үргэлж бичих. Энэ дадал яагаад чухал болохыг жишээгээр харуулна. Мөн олон мөрийг нэг тушаалаар нэмэх, текстэн дэх апостроф тэмдгийг зөв бичих аргыг сурна.
INSERT-ийг та аль хэдийн ашиглаж байсан гэдгийг сануулъя. Бүлэг 1-ийн бэлтгэлийн скриптийн хоёрдугаар хагас нь INSERT INTO тушаалууд байсан бөгөөд FastAPI сургалтын session.add() ба session.commit() хоёр ар талдаа яг энэ тушаалыг илгээдэг байсан. Энэ хичээлд бид тэр тушаалын мөр бүрийг ойлгож, өөрийн гараар бичнэ.
Эхлэхээс өмнө Бүлэг 1, Хичээл 2-т сурсан хоёр зүйлийг сэргээе, учир нь тэдгээр нь энэ бүлгийн турш чухал болно. Нэгдүгээрт, DB Browser for SQLite таны өөрчлөлтийг Write Changes (Ctrl+S) дарах хүртэл файлд хадгалдаггүй. INSERT амжилттай ажилласан ч програмаа хаахдаа хадгалахгүй гэвэл нэмсэн мөрүүд тань алга болно. Харин эсрэгээр нь, хэрэв ямар нэг юм буруу болвол Revert Changes дарж сүүлд хадгалсан байдалдаа буцаж болно — энэ бол туршилтын үеийн таны аврагч.
Хоёрдугаарт, Бүлэг 1-ийн бэлтгэлийн скриптийг хэдэн ч удаа дахин ажиллуулж өгөгдлийн сангаа эхлэл байдалд нь буцааж болно. Энэ хичээлийн төгсгөлд бид яг ингэж хийнэ, ингэснээр дараагийн хичээлүүд маань дахин нэг ижил зургаан ном, таван гишүүнээс эхэлнэ.
INSERT бол бүртгэлийн дэвтрийн дараагийн хоосон мөрөнд шинэ бичилт хийх үйлдэл юм. Үүнийг хоёр янзаар хийж болно. Эхнийх нь дэвтрийн баганын дарааллыг цээжээр мэдэж, утгуудыг зүгээр л дараалуулан бичих: “Fluent Python, Luciano Ramalho, 2015, Програмчлал, 2.” Хоёр дахь нь утга бүрийн өмнө аль баганад хамаарахыг хэлэх: "Нэр: Fluent Python; Зохиогч: Luciano Ramalho; Он: 2015; Жанр: Програмчлал; Хувь: 2."
Хоёр дахь арга нь урт боловч хоёр давуу талтай. Хэн нэгэн дэвтрийн баганын дарааллыг өөрчилсөн ч таны бичилт зөв газраа очно. Мөн та зарим нүдийг хоосон орхихыг хүсвэл зүгээр л тэр баганыг нэрлэхгүй өнгөрөхөд хангалттай. INSERT-ийн баганын жагсаалт бол яг энэ "Нэр:", "Он:" гэсэн шошгонууд юм.
Бидний books хүснэгт өмнөх (INSERT-ээс өмнөх) байдалдаа:
id | title | author | year | genre | copies
---+--------------------------+------------------+------+-------------+-------
1 | Монголын нууц товчоо | NULL | 1240 | Түүх | 2
2 | Тунгалаг Тамир | Ч.Лодойдамба | 1962 | Роман | 3
3 | Учиртай гурван толгой | Д.Нацагдорж | 1934 | Жүжиг | 1
4 | Clean Code | Robert C. Martin | 2008 | Програмчлал | 4
5 | Python Crash Course | Eric Matthes | 2015 | Програмчлал | 5
6 | The Pragmatic Programmer | Andrew Hunt | 1999 | Програмчлал | 2Номын санд шинэ ном ирлээ. Query:
sql
INSERT INTO books (title, author, year, genre, copies)
VALUES ('Fluent Python', 'Luciano Ramalho', 2015, 'Програмчлал', 2);Ажиллуулсны дараа DB Browser-ийн мессежийн талбарт 1 rows affected гэсэн мөр гарна. Энэ нь "нэг мөр өөрчлөгдлөө" гэсэн утгатай. SELECT нь “rows returned” (буцаасан мөр) гэж мэдээлдэг бол өгөгдөл өөрчлөх тушаалууд “rows affected” (нөлөөлсөн мөр) гэж мэдээлдэг. Энэ тоог харах дадал UPDATE, DELETE-ийн үед бүр ч чухал болно.
Хүснэгт INSERT-ийн дараа (SELECT * FROM books;-оор шалгавал):
id | title | author | year | genre | copies
---+--------------------------+------------------+------+-------------+-------
1 | Монголын нууц товчоо | NULL | 1240 | Түүх | 2
2 | Тунгалаг Тамир | Ч.Лодойдамба | 1962 | Роман | 3
3 | Учиртай гурван толгой | Д.Нацагдорж | 1934 | Жүжиг | 1
4 | Clean Code | Robert C. Martin | 2008 | Програмчлал | 4
5 | Python Crash Course | Eric Matthes | 2015 | Програмчлал | 5
6 | The Pragmatic Programmer | Andrew Hunt | 1999 | Програмчлал | 2
7 | Fluent Python | Luciano Ramalho | 2015 | Програмчлал | 2Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтэд title, author, year, genre, copies гэсэн баганууддаа харгалзан ‘Fluent Python’, ‘Luciano Ramalho’, 2015, 'Програмчлал', 2 гэсэн утгуудтай шинэ мөр нэм.” Одоо тушаалыг задалъя. INSERT INTO нь "дотор нь оруул" гэсэн утгатай бөгөөд араас нь хүснэгтийн нэр ирдэг. Хүснэгтийн нэрийн араас хаалт дотор баганын жагсаалт бичигддэг — энэ бол зүйрлэлийн "Нэр:", "Он:" шошгонууд. VALUES нь "утгууд" гэсэн утгатай бөгөөд араас нь хаалт дотор утгууд яг баганын жагсаалтын дарааллаар ирдэг: эхний утга эхний баганад, хоёр дахь нь хоёр дахьд гэх мэт. Текстэн утгууд дан хашилттай, тоонууд хашилтгүй — WHERE-д сурсан дүрэм энд ч хэвээр.
Бид id-ийг огт дурдаагүй ч шинэ мөр 7 гэсэн id-тай болсныг анзаараарай. Бүлэг 1-ийн скриптэд id багана INTEGER PRIMARY KEY гэж зарлагдсан бөгөөд SQLite-д ийм баганад утга өгөөгүй бол хүснэгтийн хамгийн их id дээр нэгийг нэмж автоматаар оноодог. FastAPI сургалтад шинэ тэмдэглэл үүсгэхэд id нь өөрөө гарч ирдэг байсан нь яг энэ механизм юм. PRIMARY KEY-ийн тухай Бүлэг 4-т бүтэн хичээл бий.
Жишээ 1: зарим баганыг орхих
Номын санд шинэ ном ирсэн ч зохиогч, он, хувийн тоог хараахан бүртгэж амжаагүй гэж бодъё. Нэр, жанрыг нь л мэдэж байна. Query:
sql
INSERT INTO books (title, genre)
VALUES ('Designing Data-Intensive Applications', 'Өгөгдлийн сан');Хүснэгтийн шинэ мөр (бусад мөр өөрчлөгдөөгүй):
id | title | author | year | genre | copies
---+----------------------------------------+--------+------+---------------+-------
8 | Designing Data-Intensive Applications | NULL | NULL | Өгөгдлийн сан | NULLЭнэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтэд зөвхөн title болон genre-ийг өгч шинэ мөр нэм.” Баганын жагсаалтад нэрлээгүй author, year, copies гурван багана автоматаар NULL болсон. Өмнөх бүлэгт сурсан NULL-ийн утга энд яг тохирч байна: "мэдэгдэхгүй, хараахан бүртгээгүй." Бид 0 эсвэл хоосон текст бичээгүй нь зөв — copies-д 0 бичвэл "нэг ч хувь байхгүй" гэсэн худал мэдээлэл болох байсан. id нь мөн автоматаар 8 болсон. Баганын жагсаалт нь бидэнд мэдэхгүй зүйлээ шударгаар орхих боломж олгож байна.
Энэ нь зөвхөн NULL зөвшөөрдөг баганад л ажилладаг. Хэрэв бид title-ийг орхих гэж оролдвол юу болохыг доор Түгээмэл алдаанууд хэсэгт харна.
Жишээ 2: олон мөрийг нэг тушаалаар нэмэх
Номын санд хоёр шинэ гишүүн нэгэн зэрэг элслээ. Тэднийг хоёр тусдаа INSERT-ээр нэмж болох ч нэг тушаалаар хамт нэмж болно. members хүснэгт INSERT-ээс өмнө:
id | name | city | joined_year | email
---+----------+-------------+-------------+------------------
1 | Бат | Улаанбаатар | 2023 | bat@example.com
2 | Сараа | Дархан | 2024 | saraa@example.com
3 | Тэмүүлэн | Улаанбаатар | 2022 | NULL
4 | Номин | Эрдэнэт | 2024 | nomin@example.com
5 | Ану | Улаанбаатар | 2025 | anu@example.comQuery:
sql
INSERT INTO members (name, city, joined_year, email)
VALUES
('Болд', 'Улаанбаатар', 2025, 'bold@example.com'),
('Оюун', 'Ховд', 2025, NULL);Мессежийн талбарт 2 rows affected гэж гарна. Хүснэгт INSERT-ийн дараа:
id | name | city | joined_year | email
---+----------+-------------+-------------+------------------
1 | Бат | Улаанбаатар | 2023 | bat@example.com
2 | Сараа | Дархан | 2024 | saraa@example.com
3 | Тэмүүлэн | Улаанбаатар | 2022 | NULL
4 | Номин | Эрдэнэт | 2024 | nomin@example.com
5 | Ану | Улаанбаатар | 2025 | anu@example.com
6 | Болд | Улаанбаатар | 2025 | bold@example.com
7 | Оюун | Ховд | 2025 | NULLЭнэ query юу гэж хэлж байна вэ гэвэл: “members хүснэгтэд name, city, joined_year, email баганууддаа харгалзах утгатай хоёр шинэ мөр нэм: эхнийх нь Болд, хоёр дахь нь Оюун.” VALUES-ийн араас хаалттай утгын бүлгүүд таслалаар тусгаарлагдан ирдэг бөгөөд бүлэг бүр нэг мөр болдог. Энэ бол Бүлэг 1-ийн бэлтгэлийн скриптэд зургаан номыг нэг дор нэмэхэд ашигласан хэлбэр юм. Оюуны имэйлийн оронд бид NULL-ийг ил тод бичсэнийг анзаараарай. Баганын жагсаалтад email байгаа тул түүнд заавал утга өгөх ёстой бөгөөд "мэдэгдэхгүй" гэсэн утга нь NULL — хашилтгүйгээр бичигдэнэ.
Олон мөрийн INSERT-ийн нэг чухал онцлог бий: тушаал бүхэлдээ нэг үйлдэл юм. Хэрэв хоёр дахь мөрийн утга алдаатай байвал эхний мөр ч нэмэгдэхгүй — хоёулаа хамт амжилттай болох эсвэл хоёулаа хамт цуцлагдах ёстой. Энэ "бүгд-эсвэл-юу-ч-үгүй" зан чанарыг Бүлэг 12-т transaction-ий тухай ярихдаа гүнзгий судална.
Жишээ 3: баганын жагсаалтгүй INSERT ба түүний эмзэг байдал
SQL баганын жагсаалтыг орхихыг зөвшөөрдөг. Энэ үед та хүснэгтийн бүх баганад, хүснэгтэд зарлагдсан дарааллаар утга өгөх ёстой. Query:
sql
INSERT INTO books
VALUES (9, 'Automate the Boring Stuff with Python', 'Al Sweigart', 2015, 'Програмчлал', 3);Хүснэгтийн шинэ мөр:
id | title | author | year | genre | copies
---+---------------------------------------+-------------+------+-------------+-------
9 | Automate the Boring Stuff with Python | Al Sweigart | 2015 | Програмчлал | 3Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтэд бүх зургаан баганын утгыг хүснэгтийн баганын дарааллаар өгч шинэ мөр нэм.” Ажилласан, гэвч энэ хэлбэр хэд хэдэн нуугдмал эмзэг талтай. Нэгдүгээрт, id-ийг өөрөө бичих шаардлагатай болсон — бид 9 гэдгийг хүснэгтээс харж байж мэдсэн. Хоёрдугаарт, query-г уншиж байгаа хүн 2015 нь он уу, хувийн тоо уу гэдгийг хүснэгтийн бүтцийг харахгүйгээр мэдэх аргагүй. Гуравдугаарт, хамгийн ноцтой нь: хэрэв ирээдүйд хүснэгтэд шинэ багана нэмэгдвэл (Бүлэг 4-т ALTER-ээр яг ингэж хийнэ) энэ query тэр даруй ажиллахаа больно.
Сүүлийн асуудлыг өөрийн нүдээр харахын тулд нэг утгыг санаатайгаар орхиё:
sql
INSERT INTO books
VALUES ('Automate the Boring Stuff with Python', 'Al Sweigart', 2015, 'Програмчлал', 3);Үр дүн: query ажиллахгүй бөгөөд ийм алдаа гарна:
table books has 6 columns but 5 values were suppliedЭнэ мессеж юу гэж хэлж байна вэ гэвэл: “books хүснэгт 6 баганатай, гэтэл 5 утга өгөгдсөн байна.” SQLite утгуудыг аль баганад хамааруулахаа мэдэхгүй тул татгалзсан. Хүснэгтэд нэг багана нэмэгдсэн өдөр таны програм дахь баганын жагсаалтгүй бүх INSERT яг ийм алдаа өгч эхэлнэ. Харин баганын жагсаалттай INSERT шинэ баганыг зүгээр л орхиж (NULL эсвэл анхдагч утгаар дүүргэж) хэвийн ажилласаар байх болно. Тиймээс энэ сургалтад бид баганын жагсаалтыг үргэлж бичнэ — энэ нь бичихэд хэдхэн секунд нэмдэг ч ирээдүйн өөрийгөө олон цагийн алдаа хайлтаас хамгаална.
Жишээ 4: текстэн доторх апостроф
Зарим текст дотроо апостроф (') агуулдаг, жишээ нь англи номын нэр “Don’t Make Me Think”. Гэтэл SQL-д дан хашилт нь текстийн эхлэл, төгсгөлийг заадаг. Хэрэв энгийнээр бичвэл:
sql
INSERT INTO books (title, author, year, genre, copies)
VALUES ('Don't Make Me Think', 'Steve Krug', 2000, 'Дизайн', 1);Үр дүн:
near "t": syntax errorЭнэ мессеж юу гэж хэлж байна вэ гэвэл: “t гэдэг тэмдэгтийн ойролцоо SQL-ийн дүрэм зөрчигдлөө.” SQLite 'Don' гэсэн текстийг уншаад апостроф дээр текст дууслаа гэж ойлгосон, дараа нь хашилтгүй t гэдэг үсэг ирэхэд юу болохыг мэдэхгүй болсон. Засах арга нь текст доторх апострофыг хоёр удаа давхарлаж бичих юм:
sql
INSERT INTO books (title, author, year, genre, copies)
VALUES ('Don''t Make Me Think', 'Steve Krug', 2000, 'Дизайн', 1);Хүснэгтийн шинэ мөр:
id | title | author | year | genre | copies
---+---------------------+------------+------+--------+-------
10 | Don't Make Me Think | Steve Krug | 2000 | Дизайн | 1Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтэд нэр нь Don’t Make Me Think, зохиогч нь Steve Krug гэх мэт утгатай шинэ мөр нэм.” Текст дотор хоёр дараалсан апостроф ('') нь SQL-д "энэ бол текстийн төгсгөл биш, харин жинхэнэ апостроф тэмдэгт" гэсэн утгатай. Хүснэгтэд нэг л апостроф хадгалагдсаныг анзаараарай. Энэ нь давхар хашилттай андуурагдаж болох тул анхааралтай хараарай: энэ бол хоёр дан хашилт, нэг давхар хашилт биш. Python-оос SQL илгээх үед энэ асуудлыг гараар шийддэггүй, харин параметрээр шийддэг бөгөөд үүнийг Бүлэг 11-д SQL injection-ий тухай ярихдаа үзнэ.
Энэ хичээлд бид books хүснэгтэд дөрвөн ном, members хүснэгтэд хоёр гишүүн нэмлээ. Дараагийн хичээлүүд эхлэл зургаан ном, таван гишүүнтэй хүснэгт дээр тулгуурлах тул одоо өгөгдлийн сангаа эхлэл байдалд нь буцаая. Бүлэг 1, Хичээл 2-ийн бэлтгэлийн скриптийг Execute SQL табд дахин буулгаж ажиллуулаад, Write Changes дарна. Скриптийн эхэнд байгаа DROP TABLE IF EXISTS нь өнөөдөр нэмсэн бүх мөрийг хүснэгттэй нь хамт устгаж, хүснэгтүүдийг шинээр үүсгэнэ. Хэрэв нэмсэн өөрчлөлтүүдээ хараахан хадгалаагүй байсан бол Revert Changes дарахад ч мөн адил хангалттай.
Хэрэв сонирхож байвал өөрийн уншсан дуртай хоёр номыг нэг INSERT тушаалаар нэмээд, SELECT-ээр шалгаж үзээрэй. Аль нэгнийх нь зохиогчийг мэдэхгүй бол author баганыг баганын жагсаалтаас орхиж, NULL болохыг харж болно. Дуусаад дээрх "Эхлэл байдал руу буцах" хэсгийг дахин хийхээ мартуузай. Эдгээр нь зөвхөн санал бөгөөд дараагийн хичээлүүд тэдгээрийг хийсэн гэж тооцохгүй.
Энэ хэсгийн эхний хоёр алдаа нь Бүлэг 1-ийн скриптэд хүснэгтэд тавьсан дүрмүүдтэй (constraint) холбоотой. Тэдгээрийн мөн чанарыг Бүлэг 4-т бүрэн тайлбарлана — одоохондоо зөвхөн алдааны мессежийг танихад хангалттай.
Заавал байх ёстой баганыг орхих. INSERT INTO books (author, year) VALUES ('Unknown', 2020); гэж title-гүйгээр бичвэл NOT NULL constraint failed: books.title гэсэн алдаа гарна. Энэ мессеж юу гэж хэлж байна вэ гэвэл: “books хүснэгтийн title баганад хоосон утга хориглогдсон дүрэм зөрчигдлөө.” Бэлтгэлийн скриптэд title-ийг NOT NULL гэж зарласан тул нэргүй ном бүртгэх боломжгүй. Засах арга нь баганын жагсаалтад title-ийг нэмж, утгыг нь өгөх юм.
Байгаа id-ийг дахин ашиглах. INSERT INTO books (id, title) VALUES (1, 'Шинэ ном'); гэж бичвэл UNIQUE constraint failed: books.id гэсэн алдаа гарна. Утга нь “books хүснэгтийн id баганын давхардахгүй байх дүрэм зөрчигдлөө” — 1 гэсэн id аль хэдийн "Монголын нууц товчоо"-д олгогдсон. Энэ нь иргэний бүртгэлийн дугаартай адил: хоёр хүн нэг дугаар эзэмшиж болохгүй. Ихэнх тохиолдолд хамгийн зөв шийдэл нь id-ийг огт бичихгүй, SQLite-д автоматаар олгуулах юм.
Багана, утгын тоо зөрөх. Баганын жагсаалтдаа дөрвөн багана бичээд таван утга өгвөл 5 values for 4 columns гэсэн алдаа гарна. Энэ мессеж юу гэж хэлж байна вэ гэвэл: “4 баганад 5 утга өгөгдлөө.” Ихэвчлэн нэг баганыг жагсаалтад нэмэхээ мартсан эсвэл нэг утгыг илүү бичсэнээс болдог. Баганын жагсаалт болон утгуудыг нэг нэгээр нь тулгаж шалгаарай. Баганын жагсаалтгүй INSERT-ийн үед энэ алдаа Жишээ 3-т харсан table books has 6 columns but 5 values were supplied хэлбэрээр гарна.
Текстэн доторх апостроф. Жишээ 4-т харсанчлан апострофыг давхарлахгүй бол near "...": syntax error гарна. Хашилтан доторх үг нь ихэвчлэн апострофын яг араас ирсэн хэсэг байдаг.
Write Changes дарахаа мартах. Энэ нь алдааны мессеж өгдөггүй ч хамгийн их бухимдуулдаг. INSERT амжилттай ажиллаж, SELECT-ээр шалгахад шинэ мөр харагдана, гэвч програмаа хаагаад дахин нээхэд алга болсон байна. Өгөгдөл өөрчилсөн бүрдээ Ctrl+S дарах дадал гаргаарай, эсвэл програм хаахад гарч ирэх асуултад Save гэж хариулаарай.
Энэ хичээлд та INSERT INTO ... VALUES ... тушаалаар хүснэгтэд шинэ мөр нэмж сурлаа. Баганын жагсаалт нь утга бүр аль баганад очихыг тодорхой зааж, нэрлээгүй баганыг NULL-ээр (эсвэл автомат id-аар) дүүргэх боломж олгодог бөгөөд хүснэгтийн бүтэц өөрчлөгдсөн ч query-г эвдрэхээс хамгаалдаг — тиймээс бид үүнийг үргэлж бичнэ. VALUES-ийн араас хэд хэдэн хаалттай бүлэг бичиж олон мөрийг нэг тушаалаар нэмж болно. Текстэн доторх апострофыг хоёр удаа давхарлаж бичнэ. Мөн мессежийн талбарын “rows affected” тоо болон Write Changes-ийн ач холбогдлыг дахин бататгалаа.
Дараагийн хичээлд бид UPDATE-ээр байгаа мөрийг засаж сурна. Энэ хичээл сургалтын хамгийн чухал анхааруулгуудын нэгийг агуулна: WHERE-гүй UPDATE нь алдааны мессежгүйгээр хүснэгтийн бүх мөрийг өөрчилдөг. Бид энэ гамшгийг хаях хуулбар дээр санаатайгаар үүсгэж харах бөгөөд дараа нь түүнээс хамгаалах энгийн дадлыг сурна.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.