เรียนรู้ ฐานข้อมูลและ SQL ตั้งแต่ต้น
1ฐานข้อมูลเชิงสัมพันธ์คืออะไร
ฐานข้อมูลเชิงสัมพันธ์ (relational database) เก็บข้อมูลในตาราง ตารางเหมือนสเปรดชีต: แต่ละแถวคือหนึ่งระเบียน แต่ละคอลัมน์คือหนึ่งคุณสมบัติ
ร้านค้าอาจมีตาราง customers ที่มีคอลัมน์ id, name และ city และตาราง orders ที่มีคอลัมน์ id, customer_id และ total
คีย์หลัก (primary key) คือคอลัมน์หรือชุดคอลัมน์ที่ระบุแต่ละแถวได้อย่างไม่ซ้ำ ห้ามซ้ำและห้ามว่าง ในที่นี้คือ id ของแต่ละตาราง
คีย์นอก (foreign key) คือคอลัมน์ที่อ้างถึงคีย์หลักของตารางอื่น ใน orders customer_id บอกว่าลูกค้าคนใดสั่งซื้อ
นี่คือวิธีเชื่อมตาราง: ลูกค้าหนึ่งคนมีคำสั่งซื้อได้หลายรายการ แต่แต่ละคำสั่งซื้อเป็นของลูกค้าหนึ่งคน นั่นคือความสัมพันธ์หนึ่งต่อกลุ่ม (one-to-many)
SQL (Structured Query Language) คือภาษาที่ใช้สร้างตาราง เปลี่ยนข้อมูล และถามคำถามเกี่ยวกับข้อมูล
ตรวจสอบตนเอง คีย์หลักคืออะไร
- คอลัมน์ที่อ้างถึงแถวในตารางอื่น
- คอลัมน์หรือชุดคอลัมน์ที่ระบุแต่ละแถวได้อย่างไม่ซ้ำ
- คอลัมน์แรกของทุกตาราง
- ดัชนีที่ทำให้การค้นหาเร็วขึ้น
คำตอบ: คอลัมน์หรือชุดคอลัมน์ที่ระบุแต่ละแถวได้อย่างไม่ซ้ำ. คีย์หลักไม่ซ้ำและไม่เป็น NULL จึงเลือกได้เพียงแถวเดียวพอดี คอลัมน์ที่อ้างถึงตารางอื่นคือคีย์นอก
2การอ่านข้อมูลด้วย SELECT
คำถามส่วนใหญ่เกี่ยวกับคำสั่ง SELECT ประกอบด้วยส่วนคำสั่ง (clause) ที่เขียนตามลำดับนี้เสมอ:
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …
- SELECT ระบุคอลัมน์ที่ต้องการ DISTINCT ลบแถวที่ซ้ำ
- FROM ระบุตาราง หรือตารางที่เชื่อมกัน
- WHERE เก็บเฉพาะแถวที่ตรงเงื่อนไข เช่น WHERE total > 20
- GROUP BY จัดแถวที่มีค่าเดียวกันเป็นกลุ่มเดียว เพื่อให้นับหรือรวมต่อกลุ่มได้
- HAVING เก็บเฉพาะกลุ่มที่ตรงเงื่อนไข ใช้ฟังก์ชันรวมได้ ซึ่ง WHERE ใช้ไม่ได้
- ORDER BY เรียงผลลัพธ์ จากน้อยไปมากโดยปริยาย เพิ่ม DESC เพื่อให้มากสุดก่อน
ฟังก์ชันรวม (aggregate function) สรุปหลายแถวเป็นค่าเดียว: COUNT, SUM, AVG, MIN และ MAX
ฐานข้อมูลไม่ทำงานตามลำดับที่คุณเขียน มันทำ FROM ก่อน แล้ว WHERE, GROUP BY, HAVING, SELECT และสุดท้าย ORDER BY
คำสั่งอื่นเปลี่ยนข้อมูล: INSERT เพิ่มแถว UPDATE เปลี่ยนแถว และ DELETE ลบแถว CREATE, ALTER และ DROP เปลี่ยนตารางเอง
ตรวจสอบตนเอง คุณต้องการเฉพาะลูกค้าที่มีคำสั่งซื้อมากกว่า 5 รายการ ส่วนคำสั่งใดกรองด้วย COUNT(*) > 5
- DISTINCT
- HAVING
- ORDER BY
- WHERE
คำตอบ: HAVING. ค่านับมีเมื่อแถวถูกจัดกลุ่มแล้วเท่านั้น และ HAVING กรองกลุ่ม WHERE ทำก่อนการจัดกลุ่ม จึงใช้ฟังก์ชันรวมอย่าง COUNT ไม่ได้
3การรวมตาราง นอร์มัลไลเซชัน และทรานแซกชัน
การรวมตาราง (join) รวมแถวของสองตารางโดยใช้เงื่อนไข ปกติคือคีย์นอก = คีย์หลัก:
FROM customers c JOIN orders o ON o.customer_id = c.id
- INNER JOIN (หรือ JOIN) เก็บเฉพาะแถวที่จับคู่ได้ในทั้งสองตาราง
- LEFT JOIN เก็บทุกแถวของตารางซ้าย ที่ไม่มีคู่ คอลัมน์ของตารางขวาเป็น NULL
- NULL หมายถึงค่าขาดหายหรือไม่ทราบ ทดสอบด้วย IS NULL ไม่ใช่ = NULL
นอร์มัลไลเซชัน (normalisation) แยกตารางเพื่อให้ทุกข้อเท็จจริงถูกเก็บครั้งเดียว ช่วยหลีกเลี่ยงการแก้ข้อเท็จจริงเดียวกันในหลายที่
- 1NF: ทุกเซลล์เก็บค่าอะตอมิกหนึ่งค่า ไม่มีกลุ่มที่ซ้ำ
- 2NF: 1NF และทุกคอลัมน์ที่ไม่ใช่คีย์ขึ้นกับคีย์ทั้งหมด ไม่ใช่ส่วนหนึ่งของคีย์ประกอบ
- 3NF: 2NF และไม่มีคอลัมน์ที่ไม่ใช่คีย์ขึ้นกับคอลัมน์อื่นที่ไม่ใช่คีย์
ทรานแซกชัน (transaction) จัดกลุ่มคำสั่งเป็นหน่วยเดียว COMMIT ทำให้ถาวรและ ROLLBACK ยกเลิก ทรานแซกชันเป็นไปตาม ACID: atomicity (ทำทั้งหมดหรือไม่ทำเลย) consistency isolation และ durability
ตรวจสอบตนเอง ลูกค้าไม่เคยสั่งซื้อ ลูกค้าคนนั้นเกิดอะไรขึ้นใน customers LEFT JOIN orders
- การค้นหาล้มเหลวด้วยข้อผิดพลาด
- ลูกค้าถูกตัดออกจากผลลัพธ์
- ลูกค้าปรากฏหนึ่งครั้ง โดยคอลัมน์คำสั่งซื้อเป็น NULL
- ลูกค้าปรากฏหนึ่งครั้งต่อทุกคำสั่งซื้อในตาราง
คำตอบ: ลูกค้าปรากฏหนึ่งครั้ง โดยคอลัมน์คำสั่งซื้อเป็น NULL. LEFT JOIN เก็บทุกแถวของตารางซ้ายและเติมด้านขวาที่ขาดด้วย NULL การตัดลูกค้าออกคือสิ่งที่ INNER JOIN ทำ
4วิธีทำทีละขั้น
เพื่อเขียนคิวรี หรือหาว่าคิวรีที่ให้มาคืนค่าอะไร:
- หาตารางที่เก็บข้อมูลและวิธีที่คีย์เชื่อมกัน
- เขียน FROM พร้อมการรวมตาราง เลือก LEFT JOIN เมื่อแถวที่ไม่มีคู่ต้องคงไว้
- เพิ่ม WHERE สำหรับเงื่อนไขของแต่ละแถว
- ถ้าคำถามบอกว่า “ต่อ” หรือ “สำหรับแต่ละ” ให้เพิ่ม GROUP BY และฟังก์ชันรวม
- เพิ่ม HAVING สำหรับเงื่อนไขของฟังก์ชันรวม แล้ว ORDER BY ถ้าลำดับสำคัญ
- ตรวจผลด้วยตัวอย่างเล็ก ๆ: เขียนแถวหลังแต่ละส่วนคำสั่ง ตามลำดับที่ฐานข้อมูลทำ
สำหรับคำถามทฤษฎี ให้ระบุแนวคิดก่อน (คีย์ ชนิดการรวมตาราง รูปนอร์มัล คุณสมบัติ ACID) แล้วเลือกตัวเลือกที่ตรงกับนิยามของมัน
5ตัวอย่างที่แก้ให้ดู
ทำตามทุกขั้นตอน ลองทำนายขั้นถัดไปก่อนเปิดดู
ตัวอย่างที่แก้ให้ดูตาราง customers มีแถว (1, Ana), (2, Ben) และ (3, Cas) ตาราง orders มีแถว (id, customer_id) = (10, 1), (11, 1), (12, 2) และ (13, 1) คิวรีนี้คืนค่าอะไร SELECT c.name, COUNT(o.id) FROM customers c LEFT JOIN orders o ON o.customer_id = c.id GROUP BY c.name
1ลูกค้าแต่ละคนถูกจับคู่กับคำสั่งซื้อที่มี id ของเขา Ana ตรงกับคำสั่งซื้อ 10, 11 และ 13 Ben ตรงกับคำสั่งซื้อ 12
Cas ไม่มีคำสั่งซื้อ เพราะเป็น LEFT JOIN Cas จึงคงอยู่ในผลลัพธ์ โดย o.id เป็น NULL
2- Ana, 10
- Ana, 11
- Ana, 13
- Ben, 12
- Cas, NULL
นั่นคือ 5 แถว
3GROUP BY c.name สร้างสามกลุ่ม: Ana 3 แถว Ben 1 แถว และ Cas 1 แถว
4COUNT(o.id) นับเฉพาะค่าที่ไม่ใช่ NULL Ana ได้ 3 และ Ben ได้ 1
Cas มีหนึ่งแถว แต่ o.id เป็น NULL ดังนั้น Cas ได้ 0
5Ana, Ben และ Cas รวมกันมี 3 + 1 + 0 = 4 คำสั่งซื้อ เท่ากับจำนวนแถวใน orders ถ้าใช้ COUNT(*) แทน Cas จะได้ 1 อย่างผิด ๆ เพราะ COUNT(*) นับตัวแถวเอง
คำตอบ Ana 3, Ben 1, Cas 0
6ข้อผิดพลาดที่พบบ่อย
- ใช้ฟังก์ชันรวมใน WHERE เงื่อนไขของ COUNT, SUM หรือ AVG อยู่ใน HAVING
- เขียน = NULL การเปรียบเทียบใด ๆ กับ NULL ไม่ทราบผล ใช้ IS NULL หรือ IS NOT NULL
- ใช้ INNER JOIN เมื่อแถวที่ไม่มีคู่ต้องคงไว้ ใช้ LEFT JOIN
- ลืมเงื่อนไขการรวมตาราง ถ้าไม่มี ON ทุกแถวถูกจับคู่กับทุกแถว (cross join)
- เลือกคอลัมน์ที่ไม่อยู่ใน GROUP BY และไม่อยู่ในฟังก์ชันรวม
- สับสน DELETE (ลบแถว) กับ DROP TABLE (ลบทั้งตาราง)
- รัน UPDATE หรือ DELETE โดยไม่มี WHERE มันเปลี่ยนทุกแถวในตาราง
ตรวจสอบตนเอง ตารางมี 10 แถว และคอลัมน์ col เป็น NULL ทุกแถว SELECT COUNT(col) คืนค่าอะไร
- 0
- 10
- 1
- NULL
คำตอบ: 0. COUNT(col) นับเฉพาะค่าที่ไม่ใช่ NULL จึงคืน 0 COUNT(*) นับแถวและจะคืน 10
7ข้อสอบมีหน้าตาอย่างไร
- ง่าย: ศัพท์และข้อเท็จจริงสำคัญ SELECT, WHERE, ORDER BY หรือ DELETE ทำอะไร คีย์หลักและคีย์นอก NULL หมายถึงอะไร
- ปานกลาง: การประยุกต์แนวคิด คิวรีที่ถูกต้องสำหรับงาน WHERE เทียบกับ HAVING การรวมตารางแบบ inner เทียบกับ outer รูปนอร์มัล ACID
- ยาก: กรณีศึกษาและการวิเคราะห์ ซับคิวรี ระดับการแยกตัวและความผิดปกติของมัน BCNF ฟังก์ชันหน้าต่าง ดัชนีและประสิทธิภาพคิวรี SQL injection
เมื่อให้คิวรี ให้ไล่บนไม่กี่แถวตามลำดับ FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY กับดักส่วนใหญ่ปรากฏภายในสามแถว
เรียนรู้ทีละขั้นในแอปเรียนรู้ทีละขั้นในแอป