3.4 Boolean & Filter Logic
คุณ filter “นักเรียนที่ active” — ได้ 80 คน จากทั้งหมด 100 คน แปลว่ามี 20 คนที่ไม่ active ใช่ไหม? ไม่จำเป็น — อาจมีบางคนที่สถานะเป็น “ไม่ทราบ”
Boolean: แค่ TRUE กับ FALSE?
Section titled “Boolean: แค่ TRUE กับ FALSE?”ในโลกสมบูรณ์แบบ boolean มี 2 ค่า: TRUE กับ FALSE แต่ในโลกจริงมี ค่าที่ 3: ไม่ทราบ (unknown / NULL / NaN / empty cell)
นี่คือ Kleene logic (three-valued logic):
| A | B | A AND B | A OR B |
|---|---|---|---|
| TRUE | TRUE | TRUE | TRUE |
| TRUE | FALSE | FALSE | TRUE |
| TRUE | NULL | NULL | TRUE |
| FALSE | NULL | FALSE | NULL |
| NULL | NULL | NULL | NULL |
ผลกระทบต่อ Filtering
Section titled “ผลกระทบต่อ Filtering”filter ด้วย active = TRUE ได้ 80 rows — แต่ “ไม่ active” จริงๆ แค่ 15 คน ที่เหลือ 5 คน ไม่ทราบสถานะ — หายไปเงียบๆ
สร้างข้อมูลในเซลล์ A1:B6:
| name | active |
|---|---|
| Alice | TRUE |
| Bob | FALSE |
| Carol | TRUE |
| Dave | |
| Eve | TRUE |
ลองใช้ FILTER:
=FILTER(A2:A6, B2:B6=TRUE) → Alice, Carol, Eve (3 คน)=FILTER(A2:A6, B2:B6=FALSE) → Bob (1 คน)3 + 1 = 4 — แต่มี 5 คน! Dave หายไปไหน?
=COUNTBLANK(B2:B6) → 1 (Dave!)=COUNTIF(B2:B6, TRUE) + COUNTIF(B2:B6, FALSE) + COUNTBLANK(B2:B6)→ 5 (ครบ!)ต้องนับ blank แยกเสมอ ถ้าอยากได้ภาพเต็ม
#include <stdio.h>
// C ไม่มี boolean type แท้ — ใช้ int: 0=false, 1=true// C ไม่มี NULL สำหรับ boolean — ต้องจำลองเอง
#define UNKNOWN -1#define FALSE_VAL 0#define TRUE_VAL 1
int kleene_and(int a, int b) { if (a == FALSE_VAL || b == FALSE_VAL) return FALSE_VAL; if (a == UNKNOWN || b == UNKNOWN) return UNKNOWN; return TRUE_VAL;}
int main() { printf("TRUE AND NULL = %d\n", kleene_and(TRUE_VAL, UNKNOWN)); // -1 (UNKNOWN) — ไม่ใช่ TRUE!
printf("FALSE AND NULL = %d\n", kleene_and(FALSE_VAL, UNKNOWN)); // 0 (FALSE) — ถูกต้อง เพราะ FALSE AND อะไรก็ FALSE
// ในงานจริง C ไม่มี NULL สำหรับ scalar // แต่ logic นี้คือ DNA ของ SQL NULL behavior return 0;}import pandas as pdimport numpy as np
df = pd.DataFrame({ "name": ["Alice", "Bob", "Carol", "Dave", "Eve"], "active": [True, False, True, None, True]})
# filter: เอาเฉพาะ activeactive = df[df["active"] == True]print(active)# name active# 0 Alice True# 2 Carol True# 4 Eve True# → 3 คน
not_active = df[df["active"] == False]print(not_active)# name active# 1 Bob False# → 1 คน
# 3 + 1 = 4 ≠ 5 — Dave หายไป!print(f"Total: {len(active) + len(not_active)} ≠ {len(df)}")
# หา missingunknown = df[df["active"].isna()]print(unknown)# name active# 3 Dave None# → Dave!
# วิธีที่ปลอดภัย: ใช้ .fillna() ก่อน filterdf["active_clean"] = df["active"].fillna(False)# ตอนนี้ Dave = False (ตัดสินใจชัดเจนว่า missing = ไม่ active)CREATE TABLE students ( name VARCHAR(50), active BOOLEAN);
INSERT INTO students VALUES ('Alice', TRUE);INSERT INTO students VALUES ('Bob', FALSE);INSERT INTO students VALUES ('Carol', TRUE);INSERT INTO students VALUES ('Dave', NULL);INSERT INTO students VALUES ('Eve', TRUE);
-- filter: เอาเฉพาะ activeSELECT * FROM students WHERE active = TRUE;-- Alice, Carol, Eve (3 คน)
SELECT * FROM students WHERE active = FALSE;-- Bob (1 คน)
-- 3 + 1 = 4 ≠ 5 — Dave หายไป!
-- เพราะ NULL = TRUE → NULL (ไม่ใช่ TRUE → ถูกตัดออก)-- เพราะ NULL = FALSE → NULL (ไม่ใช่ TRUE → ถูกตัดออกเหมือนกัน!)
-- หา rows ที่ missingSELECT * FROM students WHERE active IS NULL;-- Dave!
-- วิธีที่ปลอดภัย: ใช้ COALESCESELECT * FROM students WHERE COALESCE(active, FALSE) = TRUE;-- ตอนนี้ Dave ถูก treat เป็น FALSE อย่างชัดเจน
-- หรือรวม NULL เข้ามาSELECT * FROM students WHERE active IS TRUE OR active IS NULL;-- Alice, Carol, Dave, Eve (4 คน — ถ้าอยากนับ unknown ด้วย)กฎ 3 ข้อสำหรับ Boolean + NULL
Section titled “กฎ 3 ข้อสำหรับ Boolean + NULL”- นับเสมอ: ก่อน filter ให้นับ missing ก่อน —
COUNTBLANK,.isna().sum(),COUNT(*) WHERE x IS NULL - ตัดสินใจ: missing ควรถือเป็น TRUE หรือ FALSE? ใช้
COALESCE/fillnaตัดสินใจให้ชัด - ตรวจสอบ:
filter TRUE + filter FALSE + filter NULLต้องเท่ากับ total rows เสมอ