နားလည်ထားရမယ့် အချက်
Constraint ဆိုတာ data ရဲ့ ပုံစံနှင့် ခိုင်မာမှုကို ကာကွယ်ဖို့ database ကိုယ်တိုင် အတင်းအကျပ် စိုက်ဆောင်ပေးတဲ့ စည်းမျဉ်းတစ်ခုပါ။
- NOT NULL - column တစ်ခုမှာ value ရှိရမယ်
- UNIQUE - row နှစ်ခုက value မတူရဘူး
- FOREIGN KEY - value က table တခြားထဲက row အစစ်ကို ညွှန်းရမယ်
- CHECK - value က condition တစ်ခုနှင့် ကိုက်ညီရမယ်
- PRIMARY KEY - row တစ်ခုချင်းစီကို ထူးခြားစွာ ခွဲခြားပေးတဲ့ column
ဒီစည်းမျဉ်းတွေဟာ frontend form validation မှာသာမက database ထဲမှာလည်း တည်ရှိရမယ်။ frontend check တွေကို ကျော်သွားနိုင်တယ်၊ bug ကြောင့် ပျက်စီးနိုင်တယ်၊ database ကို တိုက်ရိုက်ချိတ်ဆက်တဲ့ application နောက်တစ်ခု ပေါ်လာနိုင်တယ် - database ဟာ နောက်ဆုံး ကာကွယ်ရေးလိုင်းပါ။
NULL ဆိုတာ context ပေါ်မူတည်ပြီး "မရှိခြင်း"၊ "မသိခြင်း" သို့မဟုတ် "မသက်ဆိုင်ခြင်း" ကို ဆိုလိုတယ်။ number 0 မဟုတ်၊ boolean false မဟုတ်၊ empty string "" လည်း မဟုတ်ဘူး - အဲဒါတွေက value အစစ်တွေဖြစ်ပြီး NULL ကတော့ value လုံးဝမရှိခြင်းကို ကိုယ်စားပြုတယ်။
NULL သည် 0၊ false၊ empty string မဟုတ်ပါ
ဒီသုံးခုကို NULL နှင့် တူတူတွေးမိရင် bug တွေဖြစ်တတ်တယ် - discount field က NULL ဆိုတာ discount $0 ဖြစ်တာနှင့် မတူပါဘူး၊ တစ်ခုက "မသတ်မှတ်ရသေး"၊ တစ်ခုက "တန်ဖိုးအစစ် သုညသတ်မှတ်ထား" ဖြစ်နေတယ်။ NULL ပါဝင်တဲ့ နှိုင်းယှဉ်မှုတွေက ပုံမှန်အတိုင်း မဖြစ်ဘူး - NULL က ဘာနှင့်မှ၊ NULL တစ်ခုနှင့်တောင် မတူပါ။
Normalization ဆိုတာ data ကို မလိုအပ်ဘဲ ထပ်ခါထပ်ခါ သိမ်းမနေအောင် စီစဉ်ထားတဲ့ practice ပါ - ဥပမာ user profile တစ်ခုလုံးကို order row တိုင်းမှာ ထပ်သိမ်းမည့်အစား တစ်ကြိမ်ပဲ သိမ်းပြီး orders table ကနေ ရည်ညွှန်းတာမျိုးပါ။
ဒါက duplication လျော့ချ၊ integrity ကာကွယ်၊ update ကို ပိုလုံခြုံစေတယ်။ Denormalization - data ကို တမင်ထပ်သိမ်းခြင်း - ဟာ performance အတွက် တရားဝင် trade-off တစ်ခုဖြစ်ပြီး အမှားတစ်ခု မဟုတ်ပါ။ PostgreSQL ရဲ့ "Normalization and Schema Design" သင်ခန်းစာမှာ လက်တွေ့ ဆက်လေ့လာနိုင်ပါတယ်။
- NULL
- Value ရှိခြင်းလုံးဝမရှိသည့်အခြေအနေ - context ပေါ်မူတည်ပြီး "မရှိ"၊ "မသိ" သို့မဟုတ် "မသက်ဆိုင်" ကို ဆိုလိုပြီး၊ 0၊ false၊ empty string တို့နှင့် လုံးဝ မတူပါ။
- Normalization
- Data duplication ကို လျှော့ချရန် table တွေကို fact တစ်ခုချင်းစီ တစ်နေရာတည်းသာ သိမ်းပြီး reference ဖြင့် ချိတ်ဆက်အောင် စီစဉ်ထားသော practice။
DUPLICATED DATA VS NORMALIZED REFERENCE
---------------------------------------
BAD: DUPLICATED USER DATA IN EVERY ORDER ROW
-----
orders
+----+---------+------------------+-------+
| id | name | email | total |
+----+---------+------------------+-------+
| 1 | Aye Aye | aye@example.com | 42.00 |
| 2 | Aye Aye | aye@example.com | 15.50 |
| 3 | Bo Bo | bo@example.com | 9.00 |
+----+---------+------------------+-------+
Problem: name/email repeated every row, can drift
BETTER: NORMALIZED, ORDERS REFERENCES USERS
-----
users orders
+----+---------+------+ +----+---------+-------+
| id | name | ... | | id | user_id | total |
+----+---------+------+ +----+---------+-------+
| 1 | Aye Aye | ... | | 1 | 1 | 42.00 |
| 2 | Bo Bo | ... | | 2 | 1 | 15.50 |
+----+---------+------+ | 3 | 2 | 9.00 |
+----+---------+-------+
orders.user_id references users.id (foreign key)လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Table ကို create/alter လုပ်တဲ့အခါ constraint ကို ကြေညာပေးပြီး ချိုးဖောက်မယ့် operation ကို database က ငြင်းပယ်ပါတယ်.
- duplicate email ကို ငြင်းပယ်ခြင်း
- field လိုအပ်ချက် ပျောက်နေခြင်းကို ငြင်းပယ်ခြင်း
- ဘာကိုမှ မညွှန်းတဲ့ foreign key ကို ငြင်းပယ်ခြင်း
Application code က ဒီ rejection တွေကို crash မဖြစ်အောင် friendly message ပြောင်းပေးသင့်တယ်။ NULL ကိုလည်း value ပြသ/နှိုင်းယှဉ်ခင် တိုက်ရိုက် စစ်ဆေးပါ - NULL discount field က $0 discount နှင့် မတူပါ။
Table အသစ်တွေမှာ normalized structure ကို ပုံမှန်ဦးစားပေးပါ။ Denormalization ကို တိုင်းတာထားတဲ့ အကြောင်းရင်းရှိမှ ရွေးပါ။ အောက်က runnable ဥပမာက constraint validator ရိုးရိုးလေးကို ပြသပါတယ်။
NULL သည် 0၊ false၊ empty string မဟုတ်ပါ
ဒီသုံးခုကို NULL နှင့် တူတူတွေးမိရင် bug တွေဖြစ်တတ်တယ် - discount field က NULL ဆိုတာ discount $0 ဖြစ်တာနှင့် မတူပါဘူး၊ NULL ပါဝင်တဲ့ နှိုင်းယှဉ်မှုတွေက ပုံမှန်အတိုင်း မဖြစ်ဘူး - NULL က ဘာနှင့်မှ၊ NULL တစ်ခုနှင့်တောင် မတူပါ။
အတူတူ စမ်းရေးကြည့်မယ်
function validateRow(row, existingRows, constraints) {
const results = {};
for (const field of constraints.notNull) {
const value = row[field];
const pass = value !== null && value !== undefined && value !== "";
results[`NOT NULL(${field})`] = pass;
}
for (const field of constraints.unique) {
const value = row[field];
const duplicate = existingRows.some((r) => r[field] === value);
results[`UNIQUE(${field})`] = !duplicate;
}
return results;
}
const existingUsers = [{ id: 1, name: "Aye", email: "aye@example.com" }];
const constraints = { notNull: ["name", "email"], unique: ["email"] };
console.log("Valid row:", validateRow(
{ name: "Bo", email: "bo@example.com" },
existingUsers,
constraints
));
console.log("Invalid row:", validateRow(
{ name: null, email: "aye@example.com" },
existingUsers,
constraints
));Valid row: { 'NOT NULL(name)': true, 'NOT NULL(email)': true, 'UNIQUE(email)': true }
Invalid row: { 'NOT NULL(name)': false, 'NOT NULL(email)': true, 'UNIQUE(email)': false }
name field က null ဖြစ်နေလို့ NOT NULL(name) ကျရှုံးပြီး၊ email က ရှိပြီးသား row နှင့် တူနေလို့ UNIQUE(email) လည်း ကျရှုံးပါတယ်။၅ မိနစ် စမ်းကြည့်
validateRow ကို ချဲ့ပြီး CHECK-style constraint ကို ထည့်ကြည့်ပါ - ဥပမာ "age" field က 0 ထက် ကြီးရမယ်ဆိုတဲ့ rule။ ကျရှုံးတဲ့ row တစ်ခုနှင့် အောင်မြင်တဲ့ row တစ်ခုနှင့် စမ်းကြည့်ပါ။
သတိလေးတစ်ချက်
NULL ကို 0 သို့မဟုတ် empty string နှင့် တူတူယူဆပြီး comparison logic ရေးမိခြင်း
Constraint ကို frontend form validation ထဲမှာသာ ထားပြီး database ထဲမှာ မထည့်ဘဲ ချန်ထားခြင်း
Wikipedia: Null (SQL) — How Databases Work