5.1 Schema Contracts
ลองนึกภาพ: ทีม A ส่ง CSV มาให้ทีม B ทีม B เปิดแล้วพบว่า
student_idเป็นตัวเลข (leading zeros หาย),phoneมีตัวอักษรปน,priceเป็น float แทน decimal — ทุกอย่างพัง ถ้ามี “สัญญา” กำกับไว้ตั้งแต่แรก ปัญหาเหล่านี้จะไม่เกิด
เวลาที่ใช้: ~12 นาที
Type Contract คืออะไร?
Section titled “Type Contract คืออะไร?”Type contract คือ เอกสารหน้าเดียว ที่ระบุ:
- ชื่อ column ทั้งหมด
- data type ที่ถูกต้องของแต่ละ column
- nullable หรือไม่
- constraints หรือหมายเหตุพิเศษ
ถ้าทุกคนที่สร้าง อ่าน หรือ import ข้อมูล ทำตามสัญญานี้ — ไม่มีอะไรพัง
ตัวอย่าง Type Contract: ตาราง students
Section titled “ตัวอย่าง Type Contract: ตาราง students”| Column | Type | Required | หมายเหตุ |
|---|---|---|---|
student_id | VARCHAR(6) | Yes | leading zeros! ห้ามเก็บเป็นตัวเลข |
name | VARCHAR(100) | Yes | |
phone | VARCHAR(20) | No | อนุญาตเฉพาะ digits + '+' |
price | NUMERIC(10,2) | Yes | >= 0, ห้ามใช้ float |
enrolled_on | DATE | Yes | ISO 8601 เท่านั้น (YYYY-MM-DD) |
active | BOOLEAN | Yes | default TRUE |
note | TEXT | No |
Type Contract ใน 4 เครื่องมือ
Section titled “Type Contract ใน 4 เครื่องมือ”Google Sheets ไม่มี schema enforcement ในตัว — ทุกอย่างเป็น “ใส่อะไรก็ได้”
วิธีสร้าง contract ใน Sheets:
- สร้าง sheet แยกชื่อ
_schemaเก็บตาราง contract ไว้ - ใช้ Data Validation เป็น guard:
student_id: Custom formula=AND(LEN(A2)=6, ISNUMBER(VALUE(A2)))price: ตั้ง >= 0enrolled_on: ตั้ง format เป็น Dateactive: Dropdown → TRUE / FALSE
// ตรวจ student_id ว่า 6 หลักและเป็นตัวเลข=AND(LEN(A2)=6, ISNUMBER(VALUE(A2)))
// ตรวจ phone ว่ามีแค่ตัวเลขกับ +=REGEXMATCH(B2, "^[0-9+]+$")ใน C, type contract คือ struct definition — compiler บังคับให้ทำตาม:
#include <stdio.h>#include <stdbool.h>
typedef struct { char student_id[7]; // 6 chars + null terminator char name[101]; // 100 chars + null terminator char phone[21]; // nullable = ต้องตรวจเอง double price; // ใน production ใช้ integer cents char enrolled_on[11]; // "YYYY-MM-DD" + null bool active; // default true char note[256]; // nullable} Student;
int main() { Student s = { .student_id = "001234", .name = "Somchai", .phone = "+6612345678", .price = 2500.00, .enrolled_on = "2025-01-15", .active = true, .note = "" };
printf("ID: %s, Name: %s\n", s.student_id, s.name); return 0;}Python ไม่บังคับ type เหมือน C แต่ใช้ type hints + pandas dtypes เป็น contract:
import pandas as pdfrom dataclasses import dataclassfrom typing import Optionalfrom datetime import datefrom decimal import Decimal
# วิธีที่ 1: dataclass เป็น contract@dataclassclass Student: student_id: str # VARCHAR(6) — ห้ามเป็น int! name: str phone: Optional[str] # nullable price: Decimal # ห้ามใช้ float! enrolled_on: date # ISO format active: bool = True # default TRUE note: Optional[str] = None
# วิธีที่ 2: pandas dtype mappingSTUDENT_DTYPES = { 'student_id': 'string', # ไม่ใช่ int! 'name': 'string', 'phone': 'string', # nullable 'price': 'Float64', # pandas nullable float 'enrolled_on': 'string', # parse ทีหลังด้วย pd.to_datetime 'active': 'boolean', 'note': 'string',}
# อ่าน CSV ตาม contractdf = pd.read_csv( 'students.csv', dtype=STUDENT_DTYPES, parse_dates=['enrolled_on'],)print(df.dtypes)SQL คือเครื่องมือที่ บังคับ contract ตั้งแต่ CREATE TABLE:
CREATE TABLE students ( student_id VARCHAR(6) NOT NULL, -- leading zeros! name VARCHAR(100) NOT NULL, phone VARCHAR(20), -- nullable price NUMERIC(10,2) NOT NULL CHECK (price >= 0), enrolled_on DATE NOT NULL, -- ISO only active BOOLEAN NOT NULL DEFAULT TRUE, note TEXT);
-- ลอง insert ข้อมูลที่ผิด contract:INSERT INTO students (student_id, name, price, enrolled_on)VALUES ('001234', 'Somchai', -100.00, '2025-01-15');-- ERROR: check constraint "students_price_check" is violatedทำไม Type Contract ถึงสำคัญ
Section titled “ทำไม Type Contract ถึงสำคัญ”ถ้า ไม่มี contract:
- ทีม B เปิด CSV ใน Sheets → leading zeros หาย
- ทีม C อ่านด้วย pandas →
student_idกลายเป็นint64 - ทีม D load เข้า SQL →
priceเป็นREALแทนNUMERIC
ผลลัพธ์: ข้อมูล 3 ที่ ไม่ตรงกัน
-
เขียน type contract สำหรับตาราง
ordersที่มี columns เหล่านี้:order_id(เลข 8 หลัก มี leading zeros)customer_nametotal_amount(จำนวนเงิน)order_dateshipped(จัดส่งแล้วหรือยัง)
-
ลองเขียน
CREATE TABLEstatement ใน SQL ที่ตรงกับ contract -
ลองเขียน pandas
dtypedictionary ที่ตรงกับ contract
ดูเฉลย
Type Contract:
| Column | Type | Required | หมายเหตุ |
|---|---|---|---|
order_id | VARCHAR(8) | Yes | leading zeros, ห้ามเป็น int |
customer_name | VARCHAR(100) | Yes | |
total_amount | NUMERIC(12,2) | Yes | >= 0 |
order_date | DATE | Yes | ISO 8601 |
shipped | BOOLEAN | Yes | default FALSE |
SQL:
CREATE TABLE orders ( order_id VARCHAR(8) NOT NULL, customer_name VARCHAR(100) NOT NULL, total_amount NUMERIC(12,2) NOT NULL CHECK (total_amount >= 0), order_date DATE NOT NULL, shipped BOOLEAN NOT NULL DEFAULT FALSE);pandas:
ORDER_DTYPES = { 'order_id': 'string', 'customer_name': 'string', 'total_amount': 'Float64', 'order_date': 'string', 'shipped': 'boolean',}df = pd.read_csv('orders.csv', dtype=ORDER_DTYPES, parse_dates=['order_date'])