Ачааллж байна...
Өмнөх гурван хичээлд бид хүснэгтийг анхнаас нь зөв зохиохыг сурсан: баганын төрөл сонгох, constraint тавих, PRIMARY KEY шийдэх. Гэвч бодит ертөнцөд хүснэгт нэг удаа зохиогдоод мөнхөд хэвээр үлддэггүй. Номын сан арга хэмжээ зохиож эхлэхэд шинэ мэдээлэл хадгалах шаардлага гарна, хуучин баганын нэр төөрөгдүүлэх болно, хэрэггүй болсон багана үлдэнэ. Хүснэгт амьдралынхаа туршид өөрчлөгдсөөр байдаг бөгөөд тэр өөрчлөлтийг хийх тушаал нь ALTER TABLE юм.
Энэ хичээлд ALTER TABLE-ийн дөрвөн үйлдлийг сурна: шинэ багана нэмэх, баганын нэр солих, хүснэгтийн нэр солих, багана устгах. Бүлэг 3-ын DELETE хичээлд soft delete-ийн санааг дурдаад "шинэ багана нэмэх аргыг Бүлэг 4-т сурна" гэж амласан — энэ хичээлд тэр амлалтаа биелүүлнэ.
Мөн энэ хичээл шударга хязгааруудын хичээл юм. SQLite-ийн ALTER TABLE бусад өгөгдлийн сангуудаас хамаагүй хязгаарлагдмал: байгаа баганын төрлийг өөрчлөх, байгаа баганад constraint нэмэх боломжгүй. Эдгээр хязгаарыг хэрхэн тойрдгийг харуулаад, хамгийн чухал нь хүснэгтийн бүтцийг өөрчлөх нь техникийн хүндрэлээс гадна илүү том асуудал агуулдгийг — яагаад бодит төслүүд үүнийг migration гэдэг тусгай аргаар удирддагийг харна.
Олон жил хэрэглэгдсэн бүртгэлийн дэвтрийг төсөөлөөд үзээрэй. Хэдэн зуун мөр бичигдсэн, олон хүн өдөр бүр уншдаг. Одоо маягтыг өөрчлөх хэрэгцээ гарлаа. Шинэ багана нэмэх нь хамгийн хялбар: хуудасны баруун захад шугам татаад толгойд нь шинэ нэр бичнэ. Хуучин мөрүүдийн тэр нүд хоосон үлдэнэ, эсвэл бүгдэд нь ердийн утга бичиж болно.
Баганын толгойн нэрийг солих нь техникийн хувьд хялбар — баллуураар арилгаад шинээр бичнэ — гэвч дэвтрийг ашигладаг хүн бүр хуучин нэрийг санаж байгаа. "Хувь" баганыг "Тоо ширхэг" болгон сольсон маргааш ажилтнууд "Хувь баганыг олохгүй байна" гэж ирнэ. Харин баганын төрлийг өөрчлөх — "Он" баганыг тоон бичлэгээс үгэн бичлэг рүү шилжүүлэх — нь хамгийн хүнд: ихэнхдээ шинэ дэвтэр нээж, хуучнаас мөр бүрийг хуулж бичих шаардлагатай болно. ALTER TABLE-ийн бүх хязгаар, бүх эрсдэл энэ гурван нөхцөлд аль хэдийн агуулагдаж байна.
Энэ хичээлийн бүх өөрчлөлтийг жинхэнэ books болон members хүснэгтүүд дээр хийнэ, гэхдээ Write Changes нэг ч удаа дарахгүй — хичээлийн төгсгөлд Revert Changes бүгдийг буцаана. Хэрэв санамсаргүй хадгалчихвал Бүлэг 1-ийн бэлтгэлийн скрипт таныг аварна.
Номын сан ном бүрийн хэлийг бүртгэхээр шийдлээ. 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 | Програмчлал | 2Query:
sql
ALTER TABLE books ADD COLUMN language TEXT;Хүснэгт дараа нь (SELECT * FROM books;):
id | title | author | year | genre | copies | language
---+--------------------------+------------------+------+-------------+--------+---------
1 | Монголын нууц товчоо | NULL | 1240 | Түүх | 2 | NULL
2 | Тунгалаг Тамир | Ч.Лодойдамба | 1962 | Роман | 3 | NULL
3 | Учиртай гурван толгой | Д.Нацагдорж | 1934 | Жүжиг | 1 | NULL
4 | Clean Code | Robert C. Martin | 2008 | Програмчлал | 4 | NULL
5 | Python Crash Course | Eric Matthes | 2015 | Програмчлал | 5 | NULL
6 | The Pragmatic Programmer | Andrew Hunt | 1999 | Програмчлал | 2 | NULLЭнэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтийг өөрчил: language гэсэн текстэн шинэ багана нэм.” Тушаалын бүтэц: ALTER TABLE-ийн араас ямар хүснэгтийг өөрчлөхийг, дараа нь ямар үйлдэл хийхийг бичнэ. ADD COLUMN-ий араас баганын тодорхойлолт ирэх бөгөөд энэ нь CREATE TABLE доторх тодорхойлолттой яг адилхан хэлбэртэй: нэр, төрөл, сонголттой дүрмүүд. Шинэ багана хүснэгтийн хамгийн төгсгөлд нэмэгддэг — SQLite баганыг дунд нь оруулах боломжгүй.
Хуучин зургаан мөрийн language нүд бүгд NULL боллоо. Энэ нь бүрэн үнэн: бид багана нэмсэн мөчид ямар ч номын хэлийг бүртгээгүй, тиймээс "мэдэгдэхгүй." Одоо Бүлэг 3-т сурсан UPDATE-ээр нөхье:
sql
UPDATE books SET language = 'Монгол' WHERE id IN (1, 2, 3);
UPDATE books SET language = 'Англи' WHERE id IN (4, 5, 6);Мессеж: хоёр удаа 3 rows affected. Энэ хоёр тушаал юу гэж хэлж байна вэ гэвэл: “id нь 1, 2, 3 байгаа номнуудын хэлийг 'Монгол', 4, 5, 6 байгаа номнуудынхыг 'Англи' болго.” Шинэ багана нэмэх нь ихэнхдээ хоёр алхамтай ажил: эхлээд бүтцийг өөрчлөх (ALTER), дараа нь өгөгдлийг нөхөх (UPDATE). Хоёр дахь алхмыг мартвал шинэ багана жилийн турш NULL-ээр дүүрэн хэвээр үлдэж болно.
Жишээ 1: DEFAULT-тэй багана ба soft delete
Бүлэг 3-ын DELETE хичээлд олон програм мөрийг жинхэнэ утгаар нь устгахын оронд "идэвхтэй эсэх" баганаар тэмдэглэдэг гэж сурсан. Одоо үүнийг хийе. Query:
sql
ALTER TABLE books ADD COLUMN is_available INTEGER NOT NULL DEFAULT 1;Хүснэгт (зөвхөн хамааралтай баганууд):
id | title | language | is_available
---+--------------------------+----------+-------------
1 | Монголын нууц товчоо | Монгол | 1
2 | Тунгалаг Тамир | Монгол | 1
3 | Учиртай гурван толгой | Монгол | 1
4 | Clean Code | Англи | 1
5 | Python Crash Course | Англи | 1
6 | The Pragmatic Programmer | Англи | 1Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтэд is_available гэсэн бүхэл тоон багана нэм; хоосон байж болохгүй, утга өгөөгүй бол 1 байна.” Энэ удаад хуучин мөрүүд NULL биш, 1 авсан — DEFAULT нь шинэ мөрөнд төдийгүй, багана нэмэх мөчид байгаа бүх мөрөнд үйлчилсэн. Өмнөх хичээлд SQLite-д тусдаа boolean төрөл байхгүй, үнэн/худлыг 1 ба 0-оор хадгалдаг гэж сурсан — энд 1 нь "номын санд байгаа", 0 нь "байхгүй" гэсэн утгатай.
Одоо "Учиртай гурван толгой"-г номын сангаас хасъя — гэхдээ устгалгүйгээр:
sql
UPDATE books SET is_available = 0 WHERE id = 3;
SELECT title
FROM books
WHERE is_available = 1;Үр дүн:
title
------------------------
Монголын нууц товчоо
Тунгалаг Тамир
Clean Code
Python Crash Course
The Pragmatic ProgrammerЭнэ хоёр тушаал юу гэж хэлж байна вэ гэвэл: “id нь 3 байгаа номыг байхгүй гэж тэмдэглэ; дараа нь зөвхөн байгаа номнуудын нэрийг харуул.” Гишүүдэд харагдах жагсаалтаас ном алга болсон, гэвч мэдээлэл нь хүснэгтэд бүрэн хадгалагдсан хэвээр — зохиогч, он, жанр, бүгд. Хэрэв дараа нь шинэ хувь ирвэл is_available = 1 болгоход хангалттай. Энэ бол soft delete юм. Үнэ нь мөн тодорхой: үүнээс хойш номын жагсаалт харуулах query бүрт WHERE is_available = 1 нэмэхээ санах ёстой, эс бөгөөс "устгагдсан" номнууд эргэж гарч ирнэ.
Жишээ 2: ADD COLUMN-ий хязгаарууд
ADD COLUMN нь бүх тодорхойлолтыг хүлээн авдаггүй. Хамгийн түгээмэл гурван татгалзлыг харъя. Эхлээд DEFAULT-гүй NOT NULL багана:
sql
ALTER TABLE books ADD COLUMN publisher TEXT NOT NULL;Үр дүн:
Cannot add a NOT NULL column with default value NULLЭнэ мессеж юу гэж хэлж байна вэ гэвэл: "анхдагч утга нь NULL байх NOT NULL багана нэмж болохгүй." Логик нь энгийн: багана нэмэх мөчид хуучин зургаан мөрийн publisher нүдэнд ямар нэг утга бичигдэх ёстой. DEFAULT заагаагүй тул тэр утга NULL болох байсан, гэтэл NOT NULL түүнийг хориглож байна — хоёр шаардлага зөрчилдсөн. Шийдэл нь Жишээ 1 шиг DEFAULT өгөх, эсвэл NOT NULL-гүйгээр нэмээд өгөгдлийг нөхөх юм.
Хоёрдугаарт, UNIQUE багана:
sql
ALTER TABLE books ADD COLUMN isbn TEXT UNIQUE;Үр дүн:
Cannot add a UNIQUE columnЭнэ мессеж юу гэж хэлж байна вэ гэвэл: “UNIQUE багана нэмж болохгүй.” SQLite-ийн ADD COLUMN зөвхөн хүснэгтийн төгсгөлд нүд нэмэх энгийн механизмтай бөгөөд давхардлыг хянах нэмэлт бүтэц үүсгэх чадваргүй. Үүнтэй адилаар PRIMARY KEY багана нэмж болохгүй, мөн DEFAULT-д CURRENT_TIMESTAMP шиг цаг тутам өөрчлөгддөг утга өгвөл Cannot add a column with non-constant default гэсэн алдаа гарна — "тогтмол бус анхдагч утгатай багана нэмж болохгүй."
Жишээ 3: баганын нэр солих ба түүний үр дагавар
“copies” гэдэг нэр ойлгомжгүй гэж үзээд илүү тодорхой “copy_count” болгоё. Query:
sql
ALTER TABLE books RENAME COLUMN copies TO copy_count;Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтийн copies баганын нэрийг copy_count болго.” Өгөгдөл огт өөрчлөгдөөгүй — зөвхөн толгойн нэр. Одоо Бүлэг 2-т олон удаа бичиж байсан query-гээ ажиллуулъя:
sql
SELECT title, copies
FROM books
ORDER BY copies DESC
LIMIT 3;Үр дүн:
no such column: copiesЭнэ мессеж юу гэж хэлж байна вэ гэвэл: “copies гэдэг нэртэй багана байхгүй байна.” Баганын нэрийг солих нь өгөгдлийн сангийн дотор амжилттай, аюулгүй үйлдэл байсан. Гэвч өгөгдлийн сангийн гадна — таны хадгалсан .sql файлууд, Python програм, тайлангийн скриптүүд — хуучин нэрийг ашигласаар байгаа. Тэдгээр бүгд тэр мөчид эвдэрсэн. Зүйрлэлийн "Хувь баганыг олохгүй байна" гэж ирсэн ажилтнууд яг энэ. Хэрэв энэ хүснэгт амьд вэб сайтад ашиглагдаж байсан бол сайтын номын жагсаалт тэр секундээс ажиллахаа больсон.
Хүснэгтийн нэрийг ч мөн адил солиж болно: ALTER TABLE members RENAME TO patrons; нь members хүснэгтийг patrons болгоно, үр дагавар нь ч мөн адил — members-ийг дурдсан бүх query эвдэрнэ. Дүрэм: нэр солих нь өгөгдлийн санд нэг мөр, харин түүнийг ашигладаг бүх кодонд олон мөрийн ажил. Тиймээс нэрийг анхнаас нь сайн бодож өгөх нь хамгийн хямд шийдэл юм.
Жишээ 4: багана устгах
language багана хэрэггүй гэж шийдлээ. Query:
sql
ALTER TABLE books DROP COLUMN language;Энэ query юу гэж хэлж байна вэ гэвэл: “books хүснэгтээс language баганыг бүх утгатай нь хамт устга.” Багана ба доторх зургаан утга бүрмөсөн алга болно — Бүлэг 3-ын DELETE-ийн тухай сурсан бүх анхааруулга энд ч хамаарна, гэхдээ мөрийн оронд баганаар. Өмнөх query-нүүд language-ийг ашигладаг байсан бол тэд ч эвдэрнэ.
DROP COLUMN нь бүх баганад ажилладаггүй. Мөрийн дугаарыг устгах гэж оролдъё:
sql
ALTER TABLE books DROP COLUMN id;Үр дүн:
cannot drop PRIMARY KEY column: "id"Энэ мессеж юу гэж хэлж байна вэ гэвэл: “id гэсэн үндсэн түлхүүр баганыг устгах боломжгүй.” Мөрийн хэн болохыг тодорхойлдог баганыг устгавал хүснэгт утга учраа алдана. SQLite мөн UNIQUE дүрэмтэй баганыг, дараагийн бүлэгт сурах өөр хүснэгт рүү заадаг баганыг устгахаас татгалздаг.
Одоо хүртэл бид нэмж, нэр сольж, устгалаа. Харин байгаа баганыг өөрчлөх — төрлийг нь солих, CHECK эсвэл NOT NULL нэмэх — тушаал SQLite-д огт байхгүй. Бусад өгөгдлийн санд байдаг хэлбэрийг оролдвол:
sql
ALTER TABLE books ALTER COLUMN year TEXT;Үр дүн:
near "ALTER": syntax errorЭнэ мессеж юу гэж хэлж байна вэ гэвэл: "хоёр дахь ALTER гэдэг үгийн ойролцоо SQL-ийн дүрэм зөрчигдлөө." SQLite ALTER TABLE books-ийн араас RENAME, ADD, DROP гэсэн гурван үгийн аль нэгийг л хүлээдэг. PostgreSQL-д ALTER COLUMN байдаг бөгөөд Бүлэг 10-д түүнийг ашиглана.
Тэгвэл SQLite дээр Бүлэг 4-ийн Constraints хичээлийн сургамжийг хэрэгжүүлэхийг хүсвэл — жишээ нь copies-д CHECK (copies >= 0) нэмэх — яах вэ? Цорын ганц арга нь хүснэгтийг дахин бүтээх: шинэ дүрэмтэй хүснэгт үүсгэж, өгөгдлийг хуулж, хуучныг нь устгаж, шинийн нэрийг солих. Эхлээд Revert Changes дарж хүснэгтүүдийг эхлэл байдалд нь буцаагаад, дараа нь дөрвөн алхмыг ажиллуулаарай:
sql
CREATE TABLE books_new (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT,
year INTEGER,
genre TEXT,
copies INTEGER NOT NULL DEFAULT 1 CHECK (copies >= 0)
);
INSERT INTO books_new (id, title, author, year, genre, copies)
SELECT id, title, author, year, genre, copies
FROM books;
DROP TABLE books;
ALTER TABLE books_new RENAME TO books;Энэ скрипт юу гэж хэлж байна вэ гэвэл: “copies-д шинэ дүрэмтэй books_new хүснэгт үүсгэ; books-ийн бүх мөрийг түүн рүү хуул; хуучин books-ийг устга; books_new-ийн нэрийг books болго.” Хоёр дахь алхам нь Бүлэг 3-т туслах хэрэгсэл болгон ашигласан INSERT ... SELECT хэлбэр бөгөөд баганын жагсаалтыг хоёр талд нь ил тод бичсэн нь санаатай. id-уудыг ч хуулсан тул ном бүр хуучин дугаараа хадгалсан — PRIMARY KEY-ийн хичээлийн "дугаарыг хэзээ ч бүү өөрчил" гэсэн дүрэм хамгаалагдлаа. Скриптийн дараа SELECT * FROM books; нь яг өмнөх зургаан номыг харуулах бөгөөд одоо UPDATE books SET copies = -1 WHERE id = 1; нь CHECK constraint failed гэсэн алдаа өгнө.
Энэ аргыг шударгаар үнэлье. Манай энгийн хүснэгт дээр дөрвөн алхам хангалттай байлаа. Бодит хүснэгтүүд өөр хүснэгтүүдтэй холбоотой, хурдасгах тусгай бүтэцтэй (Бүлэг 9-ийн index) байдаг бөгөөд тэдгээрийг ч бүгдийг дахин үүсгэх шаардлагатай болдог. Хэрэв дунд нь нэг алхам бүтэлгүйтвэл хагас шилжсэн хүснэгт үлдэх эрсдэлтэй. DB Browser-ийн Database Structure таб дахь Modify Table товч яг энэ ажлыг ар талдаа автоматаар хийдэг бөгөөд жижиг өөрчлөлтөд тохиромжтой. Гэхдээ гараар ч, товчоор ч — ар талд нь хүснэгт дахин бүтээгдэж байгааг мэдэж байх нь чухал. Энэ дадлагын дараа хүснэгтүүдээ эхлэл байдалд буцаахын тулд Revert Changes дахин дарна уу.
Энэ хичээлийн бүх жишээнд нэг нийтлэг зүйл бий: хүснэгтийн бүтцийн өөрчлөлт өгөгдлийн сангийн дотроо хурдан, энгийн, харин түүнийг ашигладаг бүх зүйлтэй уялдуулах нь хэцүү. Жинхэнэ програм дээр баганын нэр солих бол өгөгдлийн санг өөрчлөх, Python кодыг өөрчлөх, хоёуланг нь яг нэг мөчид шинэчлэх гэсэн гурван алхамтай ажил. Хэрэв таны програм гурван газар ажилладаг бол — таны компьютер, туршилтын server, жинхэнэ сайт — өөрчлөлт бүрийг гурван удаа, яг ижил дарааллаар хийх ёстой. Гурван сарын дараа хэн нэгэн "энэ багана хэзээ, яагаад нэмэгдсэн бэ" гэж асуувал хариулт хаана ч бичигдээгүй.
"Хөгжүүлэгчийн хэрэгсэл" сургалтад Git нь кодын өөрчлөлт бүрийг түүхтэй нь хадгалдагтай адилаар өгөгдлийн сангийн бүтцийн өөрчлөлтийг файл болгон, дугаарлан, дарааллаар нь хадгалах арга бий — үүнийг migration гэдэг. Migration файл бүр "энэ багана нэм" гэсэн нэг өөрчлөлтийг агуулж, хэрэв шаардлагатай бол түүнийг буцаах аргыг ч агуулдаг. Бүлэг 13-т бид Alembic хэрэгслээр жинхэнэ migration бичиж, хэрэглэж, буцааж үзнэ. Тэр үед энэ хичээлийн ALTER TABLE тушаалууд migration файлын дотор амьдарч эхэлнэ. Одоохондоо нэг дүгнэлт: ALTER TABLE-ийг ажиллуулах нь хялбар, харин түүнийг удирдах нь мэргэжлийн ур чадвар юм.
Хэрэв сонирхож байвал members хүснэгтэд phone TEXT гэсэн багана нэмж, хоёр гишүүнд утасны дугаар бөглөж, WHERE phone IS NOT NULL-ээр шалгаж үзээрэй. Мөн хүснэгтийг дахин бүтээх дөрвөн алхмыг members дээр давтаж, имэйлд UNIQUE дүрэм нэмж болно — скриптийн дараа ижил имэйлтэй гишүүн нэмэхийг оролдож, дүрэм ажиллаж байгааг шалгаарай. Дуусаад Revert Changes дарахаа мартуузай. Эдгээр нь зөвхөн санал бөгөөд дараагийн хичээлүүд тэдгээрийг хийсэн гэж тооцохгүй.
COLUMN гэдэг үгийг мартах. ALTER TABLE books ADD language TEXT; гэж бичвэл SQLite ажиллуулдаг — COLUMN нь ADD-ийн дараа сонголттой. Харин ALTER TABLE books RENAME copies TO copy_count; гэж бичвэл ч мөн ажилладаг. Энэ уян хатан байдал нь тушаалыг уншихад хүндрүүлдэг тул энэ сургалтад бид COLUMN-ийг үргэлж бичнэ: ADD COLUMN, RENAME COLUMN, DROP COLUMN.
Хүснэгтийн нэрийг солих, баганын нэрийг солих хоёрыг андуурах. ALTER TABLE books RENAME TO copy_count; гэж COLUMN-ийг мартвал SQLite алдаа өгөхгүй — books хүснэгтийн нэрийг copy_count болгоно! Дараагийн бүх query no such table: books гэсэн алдаа өгч эхэлнэ. Энэ үед ALTER TABLE copy_count RENAME TO books; гэж буцааж засна.
ADD COLUMN-ий араас өгөгдөл нөхөхөө мартах. Шинэ багана NULL-ээр дүүрэн үлдэх нь алдааны мессеж өгөхгүй, гэвч шинэ баганыг ашигласан query-нүүд хачин үр дүн өгнө — жишээ нь WHERE language = 'Монгол' хоосон гарна. ALTER-ийн дараа өгөгдлөө нөхөх эсвэл DEFAULT өгөхөө бодоорой.
Хүснэгт дахин бүтээхдээ баганын жагсаалтыг орхих. INSERT INTO books_new SELECT * FROM books; гэж бичвэл хоёр хүснэгтийн баганын дараалал таарч байвал ажиллана, гэвч дараалал зөрвөл утгууд буруу баганад чимээгүйхэн орно — он нь хувийн тоонд, хувийн тоо нь онд. Бүлэг 3-ын INSERT хичээлийн "баганын жагсаалтыг үргэлж бич" гэсэн дүрэм энд бүр ч чухал.
DROP TABLE-ийн дараа зогсох. Хүснэгт дахин бүтээх скриптийг алхам алхмаар ажиллуулж байгаад гуравдугаар алхмын (DROP TABLE) дараа завсарлавал таны өгөгдлийн санд books хүснэгт байхгүй, зөвхөн books_new үлдсэн байна. Бүх query эвдэрнэ. Скриптийг бүтнээр нь нэг дор ажиллуулаарай. Бүлэг 12-т transaction-ий тухай сурахдаа ийм олон алхамт ажлыг "бүгд-эсвэл-юу-ч-үгүй" болгох аргыг харна.
Энэ хичээлд та ALTER TABLE-ээр байгаа хүснэгтийг өөрчилж сурлаа. ADD COLUMN нь хүснэгтийн төгсгөлд багана нэмдэг; хуучин мөрүүд NULL эсвэл DEFAULT утгыг авна, харин SQLite DEFAULT-гүй NOT NULL, UNIQUE, PRIMARY KEY багана нэмэхийг зөвшөөрдөггүй. Шинэ баганаар soft delete-ийг хэрэгжүүлж, мөрийг устгалгүйгээр "байхгүй" гэж тэмдэглэлээ. RENAME COLUMN болон RENAME TO нь өгөгдлийг хөндөхгүй ч хуучин нэрийг ашигладаг бүх кодыг эвддэг. DROP COLUMN нь баганыг утгатай нь бүрмөсөн устгадаг бөгөөд PRIMARY KEY-д ажиллахгүй. SQLite-д баганын төрөл болон constraint-ыг өөрчлөх тушаал байхгүй тул хүснэгтийг шинээр үүсгэж, өгөгдлийг хуулж, хуучныг устгаж, нэрийг солих дөрвөн алхмаар тойрно. Бүтцийн өөрчлөлтийг кодтой уялдуулах хэрэгцээ нь Бүлэг 13-ын migration-ий үндэс юм.
Ингээд Бүлэг 4 дууслаа — та одоо хүснэгтийг үүсгэж, дүрэмтэй болгож, түлхүүр сонгож, өөрчилж чадна. Гэвч бидний бүх хүснэгт одоогоор ганцаардмал: books болон members бие биеэ мэддэггүй. Дараагийн бүлэгт бид хүснэгтүүдийг хооронд нь холбоно. Нэг хүснэгтийн мөр өөр хүснэгтийн мөр рүү FOREIGN KEY-ээр заах бөгөөд энэ нь өгөгдлийн сангийн "харилцан холбоотой" (relational) гэдэг нэрийн жинхэнэ утга юм.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.