Ачааллж байна...
Өгөгдлийн амьдралын мөчлөг гурван үе шаттай: төрөх (INSERT), өөрчлөгдөх (UPDATE), алга болох (DELETE). Өмнөх хоёр хичээлд бид эхний хоёрыг сурсан бол энэ хичээлд сүүлчийнхийг нь сурна. Гишүүн номын сангаас гарах, ном алдагдах, буруу оруулсан бүртгэлийг арилгах — эдгээр бүгд DELETE-ийн ажил. FastAPI сургалтын устгах endpoint дээрх session.delete() нь ар талдаа яг энэ тушаалыг илгээдэг байсан.
DELETE-ийн бичлэг гурван тушаалын дотроос хамгийн энгийн нь — баганын жагсаалт ч, SET ч байхгүй. Харин аюул нь хамгийн том нь. Өмнөх хичээлд харсан WHERE-гүй UPDATE хүснэгтийн бүх утгыг эвдсэн ч мөрүүд ядаж хүснэгтэд үлдсэн байсан — номын нэр, зохиогч нь хэвээрээ байсан. WHERE-гүй DELETE харин мөрүүдийг өөрсдийг нь бүрмөсөн арилгадаг. Үлдэх зүйл байхгүй.
Тиймээс энэ хичээл өмнөх хичээлийн бүтцийг дагана: дасгалын хуулбар дээр ажиллаж, гамшгийг өөрийн нүдээр харж, эхлээд SELECT, дараа нь DELETE гэсэн дадлыг бататгана. Үүнээс гадна хоёр шударга сэдвийг хөндөнө: мөр устгах болон хүснэгт бүхэлд нь устгах хоёрын ялгаа, мөн устгагдсан өгөгдлийг сэргээх бодит боломж хэр байдаг вэ гэдэг.
Хэрэв UPDATE нь баллуураар нэг нүдийг арилгаад шинээр бичих үйлдэл байсан бол DELETE нь дэвтрээс бүтэн мөрийг хайчаар хайчилж аваад хаях үйлдэл юм. Хайчилсан мөр дэвтэрт ул мөр ч үлдээхгүй. WHERE бол хайчийг хаана тавихыг заадаг харандааны тэмдэг: "энэ мөрийг л хайчил." Тэмдэггүйгээр хайч барьсан хүнд "хайчил" гэж тушаавал тэр дэвтрийн бүх хуудсыг хайчилна — гэхдээ дэвтрийн хавтас, баганын толгойнууд үлдэнэ.
Энэ сүүлийн нарийн зүйл чухал. DELETE нь мөрүүдийг устгадаг ч хүснэгтийг өөрийг нь устгадаггүй. Хоосорсон дэвтэр шинэ бичилт хүлээн авахад бэлэн хэвээр байна. Харин дэвтрийг бүхэлд нь шатааж, тавиураас алга болгох өөр нэг тушаал бий — DROP TABLE. Энэ хоёрыг андуурах нь элбэг тул доор тусад нь харьцуулна.
Энэ удаад бид members хүснэгтийн хуулбар дээр ажиллана. Execute SQL табд ажиллуулаарай:
sql
CREATE TABLE members_practice AS SELECT * FROM members;Өмнөх хичээлийн нэгэн адил энэ нь “members хүснэгтийг бүхэлд нь уншаад, тэр үр дүнгээр members_practice гэсэн шинэ хүснэгт үүсгэ” гэсэн утгатай. Мөн өмнөх хичээлийн нэгэн адил энэ хичээлийн турш Write Changes дарахгүй, төгсгөлд нь Revert Changes дарж бүгдийг арилгана.
Бидний members_practice хүснэгт DELETE-ээс өмнө:
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Номин гишүүнчлэлээ цуцаллаа. Өмнөх хичээлийн дадлын дагуу эхлээд SELECT хийнэ:
sql
SELECT *
FROM members_practice
WHERE id = 4;Үр дүн:
id | name | city | joined_year | email
---+-------+---------+-------------+------------------
4 | Номин | Эрдэнэт | 2024 | nomin@example.comЭнэ query юу гэж хэлж байна вэ гэвэл: “members_practice хүснэгтээс id нь 4 байгаа мөрийг бүхэлд нь харуул.” Нэг мөр, зөв хүн. Одоо query-ний эхний мөрийг солино. Энд UPDATE-ээс ч хялбар: SELECT *-ийг DELETE гэсэн ганц үгээр солиход л хангалттай, FROM болон WHERE мөрүүд яг хэвээрээ үлдэнэ:
sql
DELETE
FROM members_practice
WHERE id = 4;Мессеж: 1 rows affected. Хүснэгт DELETE-ийн дараа:
id | name | city | joined_year | email
---+----------+-------------+-------------+------------------
1 | Бат | Улаанбаатар | 2023 | bat@example.com
2 | Сараа | Дархан | 2024 | saraa@example.com
3 | Тэмүүлэн | Улаанбаатар | 2022 | NULL
5 | Ану | Улаанбаатар | 2025 | anu@example.comЭнэ query юу гэж хэлж байна вэ гэвэл: “members_practice хүснэгтээс id нь 4 байгаа мөрийг устга.” DELETE тушаал гурван хэсэгтэй: DELETE гэсэн үг, FROM-ийн араас хүснэгтийн нэр, WHERE-ийн араас аль мөрийг устгахыг заасан нөхцөл. Баганын жагсаалт байхгүй нь ойлгомжтой — DELETE нь мөрийг бүхэлд нь устгадаг тул "аль баганыг" гэсэн асуулт утгагүй.
Энэ хэлбэрийн бас нэг давуу тал бий. SELECT болон DELETE хоёр ижил FROM, ижил WHERE-тэй тул DELETE нь “SELECT-ийн харуулсан мөрүүдийг устга” гэсэн утгатай болж байна. Тиймээс SELECT-ийн үр дүн нь DELETE юуг устгах гэж байгааг яг таг урьдчилан харуулсан зураг юм. Мессеж дэх “1 rows affected” нь SELECT-ийн нэг мөртэй таарч байна. Мөн id 4 устсан ч бусад мөрийн id өөрчлөгдөөгүйг анзаараарай — 3-ын араас 5 ирж байна. Иргэний бүртгэлийн дугаартай адил, нэг хүн гарсан нь бусдын дугаарыг шилжүүлдэггүй.
Жишээ 1: нөхцлөөр олон мөр устгах
Номын сан Улаанбаатар дахь салбараа хаалаа гэж бодъё (зөвхөн дасгалын хуулбар дээр!). Хүснэгт одоо дээрх дөрвөн мөртэй. Эхлээд SELECT:
sql
SELECT *
FROM members_practice
WHERE city = 'Улаанбаатар';Үр дүн:
id | name | city | joined_year | email
---+----------+-------------+-------------+----------------
1 | Бат | Улаанбаатар | 2023 | bat@example.com
3 | Тэмүүлэн | Улаанбаатар | 2022 | NULL
5 | Ану | Улаанбаатар | 2025 | anu@example.comЭнэ query юу гэж хэлж байна вэ гэвэл: “members_practice хүснэгтээс city нь 'Улаанбаатар' байгаа мөрүүдийг харуул.” Гурван мөр — эдгээр гурван хүн устгагдах гэж байна. Үргэлжлүүлье:
sql
DELETE
FROM members_practice
WHERE city = 'Улаанбаатар';Мессеж: 3 rows affected. Хүснэгт DELETE-ийн дараа:
id | name | city | joined_year | email
---+-------+--------+-------------+------------------
2 | Сараа | Дархан | 2024 | saraa@example.comЭнэ query юу гэж хэлж байна вэ гэвэл: “members_practice хүснэгтээс city нь 'Улаанбаатар' байгаа бүх мөрийг устга.” SELECT гурван мөр харуулсан, DELETE гурван мөрөнд нөлөөлсөн — тоонууд таарч байна. Энэ жишээ нь DELETE-ийн WHERE нь Бүлэг 2-т сурсан бүх хэрэгслийг — харьцуулалт, AND, OR, LIKE, IN, BETWEEN, IS NULL — хүлээн авдгийг харуулж байна. Гэхдээ энэ нь давхар иртэй хутга: WHERE хэдий чинээ нарийн төвөгтэй болно, санамсаргүй илүү мөр барих эрсдэл төдий чинээ өснө. Тиймээс нөхцөл хэдий чинээ төвөгтэй байна, SELECT-ийн үр дүнг төдий чинээ анхааралтай уншаарай.
Жишээ 2: WHERE-гүй DELETE
Одоо гамшгийг харъя. Энэ query-г зөвхөн members_practice дээр ажиллуулаарай. Хүснэгтэд одоо ганц мөр үлдсэн ч гамшгийн мөн чанар мөрийн тооноос хамаарахгүй. Илүү бодитой харагдуулахын тулд эхлээд хуулбараа дахин дүүргэе:
sql
DELETE FROM members_practice WHERE id = 2;
INSERT INTO members_practice SELECT * FROM members;Энэ хоёр мөр юу гэж хэлж байна вэ гэвэл: "эхлээд үлдсэн ганц мөрийг устгаад, дараа нь members хүснэгтийн бүх мөрийг members_practice руу хуулж оруул." Хоёр дахь мөр нь INSERT-ийн VALUES-ийн оронд SELECT-ийн үр дүнг ашигладаг хэлбэр бөгөөд энд зөвхөн туслах хэрэгсэл болгон ашиглаж байна. SELECT * FROM members_practice; ажиллуулбал таван гишүүн бүгд эргэж ирсэн байна. Одоо:
sql
DELETE FROM members_practice;Мессеж: 5 rows affected. Хүснэгт DELETE-ийн дараа (SELECT * FROM members_practice;):
id | name | city | joined_year | email
---+------+------+-------------+------
(хоосон — 0 мөр)Энэ query юу гэж хэлж байна вэ гэвэл: “members_practice хүснэгтээс мөрүүдийг устга.” Аль мөрийг гэж хэлээгүй тул бүгдийг. Таван гишүүн, тэдний нэр, хот, имэйл — бүгд алга. Үр дүнгийн хүснэгтэд баганын толгойнууд үлдсэнийг анзаараарай: хүснэгт өөрөө байсаар байна, зөвхөн хоосон болсон. Хайчилсан дэвтрийн хавтас үлджээ.
Өмнөх хичээлийн WHERE-гүй UPDATE-тэй харьцуулъя. Тэнд хувийн тоонууд 0 болсон ч номын нэр, зохиогч үлдсэн байсан тул ядаж "аль ном" гэдгийг мэдэж байсан — хувийн тоог тавиураас дахин тоолж сэргээх боломжтой байсан. Энд харин хэн гишүүн байсныг ч мэдэх аргагүй. Тэдний имэйл хаяг алга тул тэдэнтэй холбогдож "та дахин бүртгүүлнэ үү" гэж хэлэх ч боломжгүй. DELETE-ийн гамшиг UPDATE-ийнхээс нэг шат илүү гүн байдаг шалтгаан энэ юм.
Жишээ 3: DELETE ба DROP TABLE
Хүснэгт хоосорсон боловч амьд хэвээр гэдгийг нотлохын тулд түүнд шинэ мөр нэмж болно: INSERT INTO members_practice SELECT * FROM members; ажиллуулбал таван гишүүн дахин орж ирнэ. Одоо хүснэгтийг өөрийг нь устгадаг тушаалыг харъя:
sql
DROP TABLE members_practice;Мессеж нь мөрийн тоо хэлэхгүй, зүгээр л амжилттай гэж мэдээлнэ. Одоо уншихыг оролдоё:
sql
SELECT * FROM members_practice;Үр дүн:
no such table: members_practiceЭнэ мессеж юу гэж хэлж байна вэ гэвэл: “members_practice гэдэг нэртэй хүснэгт байхгүй байна.” DROP TABLE нь мөрүүдийг ч, баганын тодорхойлолтыг ч, хүснэгтийн нэрийг ч — бүгдийг нь устгасан. Database Structure табд ч тэр хүснэгт алга болсон байна. Зүйрлэлээр бол DELETE дэвтрийн хуудсуудыг хайчилсан, DROP TABLE дэвтрийг бүхэлд нь шатаасан.
Энэ хоёрыг хэзээ ашиглах вэ? DELETE нь өдөр тутмын өгөгдлийн ажилд — гишүүн гарах, бүртгэл арилгах — хэрэглэгддэг бөгөөд програмын кодонд байнга гарч ирдэг. DROP TABLE нь хүснэгтийн бүтцийн өөрчлөлт бөгөөд маш ховор, тусгай шалтгаантай үед л хийгддэг. Бүлэг 1-ийн бэлтгэлийн скриптийн эхэнд байсан DROP TABLE IF EXISTS-ийг одоо бүрэн ойлгож байгаа байх: "хэрэв энэ хүснэгт байвал шатаа, дараа нь шинээр үүсгэнэ." Энэ нь зөвхөн бэлтгэлийн скриптэд л тохиромжтой, учир нь тэнд бид өгөгдлөө санаатайгаар эхнээс нь эхлүүлж байгаа.
Мөн TRUNCATE гэдэг гурав дахь тушаалын нэрийг сонсож магадгүй. PostgreSQL зэрэг олон өгөгдлийн санд TRUNCATE нь хүснэгтийн бүх мөрийг маш хурдан устгаж, хүснэгтийг өөрийг нь үлдээдэг — WHERE-гүй DELETE-тэй ижил үр дүн, гэхдээ том хүснэгтэд хамаагүй хурдан. SQLite-д TRUNCATE тушаал байдаггүй: TRUNCATE TABLE members; гэж бичвэл near "TRUNCATE": syntax error гарна. SQLite-д үүний оронд WHERE-гүй DELETE ашиглах бөгөөд SQLite түүнийг дотроо хурдан арга руу автоматаар шилжүүлдэг.
Одоо бүх хүн асуудаг асуултад шударга хариулъя: DELETE хийсэн мөрийг буцааж авч болох уу? Энэ хичээлд бид Revert Changes дарж бүгдийг сэргээх гэж байгаа ч энэ нь зөвхөн нэг нөхцөлд ажилладаг: DB Browser-т өөрчлөлтүүд хараахан Write Changes-ээр хадгалагдаагүй байх. Write Changes дарсны дараа, эсвэл Python, psql зэргээс шууд хадгалагддаг тушаал ажиллуулсны дараа SQL-ийн хувьд "буцаах" (undo) тушаал байдаггүй. Устгагдсан мөр устгагдсан.
Тэгвэл бодит амьдралд хүмүүс устгасан өгөгдлөө хэрхэн сэргээдэг вэ? Цорын ганц найдвартай хариулт бол нөөц хуулбар (backup) юм — өгөгдлийн сангийн өмнөх үеийн хуулбар өөр газар хадгалагдсан байх. Backup байгаа бол түүнээс өгөгдлөө сэргээж болно, байхгүй бол өгөгдөл үүрд алга болсон. Энд нэг чухал санааг онцолъя: backup нь асуудал гарсны дараа хийгддэггүй, харин асуудал гарахаас өмнө хийгдсэн байх ёстой. Бүлэг 15-д бид PostgreSQL-ийн backup хийх, түүнээс сэргээх хэрэгслийг жинхэнэ ашиглаж үзнэ.
SQLite-ийн хувьд энэ хамгаалалт гайхмаар энгийн. Өгөгдлийн сан бүхэлдээ нэг файл тул backup гэдэг нь зүгээр л тэр файлын хуулбар юм. Том өөрчлөлт хийхээсээ өмнө DB Browser-т хадгалаагүй өөрчлөлт байхгүй эсэхийг шалгаад, File Explorer-оор library.db файлыг хуулж library-backup.db гэх мэт нэрээр хадгалахад хангалттай. Хэрэв ямар нэг юм буруу болвол эвдэрсэн файлыг backup-аар сольж болно. Энэ бол таван секундын ажил бөгөөд ирээдүйд таныг олон цагийн бухимдлаас аварч болох дадал юм.
Мөн олон бодит програм мөрийг жинхэнэ утгаар нь устгахаас зайлсхийдэг гэдгийг мэдэж байх нь сонирхолтой. Тэд хүснэгтэд "идэвхтэй эсэх" гэх мэт нэмэлт багана байлгаж, хэрэглэгчийг "устгах" үед DELETE-ийн оронд UPDATE-ээр тэр баганыг өөрчилдөг. Мөр хүснэгтэд үлдэх тул шаардлагатай үед буцааж идэвхжүүлж болно. Үүнийг soft delete гэж нэрлэдэг бол жинхэнэ DELETE-ийг hard delete гэдэг. Хоёулаа өөр өөр зориулалттай: soft delete нь буцаах боломж олгодог, hard delete нь өгөгдлийг үнэхээр арилгадаг (жишээ нь хэрэглэгч өөрийн мэдээллийг бүрмөсөн устгуулахыг хүсвэл). Шинэ багана нэмэх аргыг Бүлэг 4-т сурах бөгөөд тэр үед энэ санаа илүү тодорхой болно.
Бид Write Changes огт дараагүй тул хэрэгслийн мөрөөс Revert Changes дараад зөвшөөрнө. members_practice хүснэгт (хэрэв таны туршилтаас үлдсэн бол) болон түүнтэй холбоотой бүх өөрчлөлт алга болж, өгөгдлийн сан хичээлийн эхэн дэх байдалдаа буцна. Database Structure табд зөвхөн books болон members байгаа, members таван гишүүнтэйгээ байгаа эсэхийг шалгаарай.
Хэрэв сонирхож байвал File Explorer-оор library.db файлын backup хуулбарыг хийж үзээрэй (DB Browser-т хадгалаагүй өөрчлөлт байхгүй байх үед). Дараа нь дасгалын хуулбар үүсгэхийн оронд санаатайгаар жинхэнэ members хүснэгтээс нэг гишүүнийг устгаж, Write Changes дараад, DB Browser-оо хаана. Эцэст нь library.db файлыг устгаж, backup хуулбарын нэрийг library.db болгон өөрчлөөд DB Browser-оор дахин нээгээрэй — устгасан гишүүн буцаж ирсэн байна. Энэ нь backup-ийн үнэ цэнийг өөрийн гараар мэдрэх хамгийн хурдан арга юм. Хэрэв ямар нэг юм замбараагүй болвол Бүлэг 1-ийн бэлтгэлийн скрипт таныг үргэлж аварна. Эдгээр нь зөвхөн санал бөгөөд дараагийн хичээлүүд тэдгээрийг хийсэн гэж тооцохгүй.
WHERE мартах. Жишээ 2-т харсанчлан алдааны мессеж гарахгүй, хүснэгт чимээгүйхэн хоосорно. “rows affected” тоо хүснэгтийн бүх мөрийн тоотой тэнцүү гарвал энэ нь цорын ганц дохио юм. Хамгаалалт нь өмнөх хичээлийн нэгэн адил: эхлээд ижил WHERE-тэй SELECT, дараа нь SELECT *-ийг DELETE-ээр солих.
DELETE * гэж бичих. SELECT-ээс хувиргахдаа *-ийг устгахаа мартаж DELETE * FROM members_practice WHERE id = 4; гэж бичвэл near "*": syntax error гарна. Энэ мессеж юу гэж хэлж байна вэ гэвэл: "од тэмдэгтийн ойролцоо SQL-ийн дүрэм зөрчигдлөө." DELETE нь үргэлж бүтэн мөрийг устгадаг тул "бүх багана" гэж заах шаардлагагүй — SQL энэ хэлбэрийг хүлээн авдаггүй. SELECT * гэсэн хоёр үгийг хоёуланг нь DELETE-ээр солих хэрэгтэй.
Нэг утгыг DELETE-ээр арилгах гэж оролдох. Тэмүүлэнгийн имэйлийг арилгах гэж DELETE email FROM members WHERE id = 3; гэж бичвэл near "email": syntax error гарна. DELETE нь мөр устгадаг, нүд биш. Нэг нүдний утгыг арилгах нь өгөгдлийг өөрчлөх үйлдэл тул UPDATE-ийн ажил: UPDATE members SET email = NULL WHERE id = 3;. Өөрөөр хэлбэл "энэ хүний имэйлийг мэдэхгүй болсон" гэдэг бол UPDATE, "энэ хүн бүртгэлээс гарсан" гэдэг бол DELETE.
DELETE болон DROP TABLE-ийг андуурах. Хүснэгтийг цэвэрлэх гэж DROP TABLE ашиглавал хүснэгт бүхэлдээ алга болж, дараагийн INSERT-үүд no such table алдаа өгнө. Эсрэгээр, хүснэгтийг бүрмөсөн арилгах гэж WHERE-гүй DELETE ашиглавал хоосон хүснэгт Database Structure табд үлдсээр байна. "Мөрүүдээс салах уу, хүснэгтээс салах уу" гэж өөрөөсөө асуугаарай.
Тодруулсан хэсгийг л ажиллуулах. Өмнөх хичээлд анхааруулсанчлан гурван мөрт DELETE-ийн эхний хоёр мөрийг л тодруулаад F5 дарвал зөвхөн DELETE FROM members_practice ажиллаж, WHERE-гүй DELETE болно. DELETE-ийн хувьд энэ нь UPDATE-ийнхээс ч илүү хор хөнөөлтэй. DELETE ажиллуулахын өмнө бичих талбарт юу тодорсон байгааг заавал шалгаарай.
Энэ хичээлд та DELETE FROM ... WHERE ... тушаалаар мөр устгаж сурлаа. Баганын жагсаалт байхгүй, учир нь DELETE үргэлж бүтэн мөрийг устгадаг. Хамгаалалтын дадал нь UPDATE-ийнхээс ч хялбар: ижил WHERE-тэй SELECT ажиллуулж шалгаад, SELECT *-ийг DELETE-ээр солиод, “rows affected”-ийг харьцуулна. WHERE-гүй DELETE хүснэгтийн бүх мөрийг чимээгүйхэн устгадаг, харин хүснэгтийг өөрийг нь үлдээдэг — хүснэгтийг бүхэлд нь устгадаг нь DROP TABLE юм. SQLite-д TRUNCATE байдаггүй. Устгагдсан өгөгдлийг SQL-ээр буцааж авах арга байхгүй тул цорын ганц найдвартай хамгаалалт нь урьдчилан хийсэн backup бөгөөд SQLite-д энэ нь файлын энгийн хуулбар юм.
Ингээд Түвшин 1-ийн бүх ур чадвар бүрдлээ: та өгөгдлийг уншиж, шүүж, эрэмбэлж, нэмж, засаж, устгаж чадна. Дараагийн хичээл бол Түвшин 1-ийн төгсгөлийн удирдамжтай дасгал юм. Бид шинэ өгөгдлийн сан үүсгэж — таны үзсэн киноны жагсаалт — түүнийг дүүргэж, засаж, асууж, энэ түвшинд сурсан бүх ур чадвараа нэг төсөлд нэг удаа ашиглана.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.