บทที่ 1 บทบาท DBA
บทที่ 2 สภาพแวดล้อม DB
บทที่ 3 Change Management
บทที่ 4 Availability & HA
1 การบริหารจัดการฐานข้อมูลและบทบาทของ DBA
1. องค์ประกอบหลักของระบบ
Database : แหล่งจัดเก็บข้อมูลกลางที่มีโครงสร้างและกฎเกณฑ์ชัดเจน
DBMS (Database Management System) : ซอฟต์แวร์กลางควบคุมการเข้าถึง ความปลอดภัย และประสิทธิภาพของฐานข้อมูล
Application : โปรแกรมประยุกต์เชื่อมต่อกับ DBMS เพื่อดึงหรือบันทึกข้อมูลไปให้บริการกับผู้ใช้
DBA (Database Administrator) : ผู้รับผิดชอบดูแลระบบให้ปลอดภัย ถูกต้อง พร้อมใช้งาน และรวดเร็ว
2. ความสำคัญของการบริหารฐานข้อมูลต่อองค์กร
สนับสนุนการตัดสินใจ : ให้บริการข้อมูลที่ถูกต้อง แม่นยำ และทันเวลาแก่ผู้บริหารทุกระดับ
ลดความเสี่ยงระบบ : ป้องกันข้อมูลสูญหาย ข้อมูลรั่วไหล หรือเหตุการณ์ระบบหยุดทำงาน (Downtime)
ใช้ข้อมูลร่วมกัน : ลดความซ้ำซ้อนของข้อมูล ให้ทุกแอปพลิเคชันอ้างอิงและใช้ข้อมูลชุดเดียวกัน (Single Source of Truth)
3. DBA เชิงรับ (Reactive) vs DBA เชิงรุก (Proactive)
ประเด็น
Reactive DBA (เชิงรับ)
Proactive DBA (เชิงรุก)
แนวทาง
รอให้เกิดปัญหาก่อนแล้วจึงแก้ไขเฉพาะหน้า (Firefighting)
วิเคราะห์ความเสี่ยงและหาวิธีป้องกันก่อนเกิดปัญหาจริง
จุดเน้น
เน้นแก้ไข Incident เหตุการณ์ระบบล่ม/ทำงานช้า
เน้น Monitoring, Capacity Planning & SQL Tuning ล่วงหน้า
มุมมองเวลา
ระยะสั้น แก้ปัญหาเฉพาะหน้าแบบวันต่อวัน
ระยะยาว วางแผนสถาปัตยกรรมรองรับการเติบโตธุรกิจ
ผลลัพธ์
ระบบกลับมาใช้ได้เป็นครั้งคราว เสี่ยงต่อการเกิดปัญหาซ้ำ
ลดโอกาสเกิดปัญหาและลดผลกระทบเชิงลบต่อธุรกิจ
4. ขอบเขตงานของผู้เกี่ยวข้องกับฐานข้อมูล
Data Management : เน้นด้านธุรกิจและการกำกับดูแล เช่น นโยบายข้อมูล เจ้าของข้อมูล คุณภาพ และมาตรฐานการใช้ข้อมูล
Database Administration (DBA) : เน้นเทคนิคฐานข้อมูล เช่น ออกแบบ Schema, การสำรองข้อมูล (Backup), ควบคุมสิทธิ์ และปรับจูนประสิทธิภาพ
System Administration (SysAdmin) : เน้นโครงสร้างพื้นฐาน เช่น ติดตั้งระบบปฏิบัติการ (OS), เครือข่าย (Network) และฮาร์ดแวร์เซิร์ฟเวอร์
5. หน้าที่หลักของ DBA (Core Responsibilities)
Database Design : กำหนดโครงสร้างตาราง ความสัมพันธ์ Primary/Foreign Key, Index และ Constraint
Performance & Tuning : ติดตามการใช้ทรัพยากร วิเคราะห์ Query execution plan และปรับแต่งระบบให้ตอบสนองเร็ว
Availability & Security : ดูแลระบบให้พร้อมใช้ตามข้อตกลง SLA, กำหนด Role, สิทธิ์เข้าถึงของผู้ใช้ และตรวจสอบ Audit Log
Backup & Recovery : กำหนดนโยบายและรอบการสำรองข้อมูล, ทดสอบกู้คืนจริง (Restore Test) และเตรียมแผน Disaster Recovery (DR)
Data Integrity : รักษาความถูกต้อง ความครบถ้วน และความสอดคล้องกันของข้อมูลทั่วทั้งระบบ
6. ประเภทและบทบาทเฉพาะทางของ DBA
System DBA : ดูแลระดับโครงสร้างพื้นฐาน ติดตั้ง ตั้งค่า และดูแลแพลตฟอร์มเซิร์ฟเวอร์ DBMS
Database Architect & Modeler : เน้นออกแบบสถาปัตยกรรมฐานข้อมูลระดับใหญ่และแบบจำลองข้อมูลเชิงธุรกิจ
Application DBA : ดูแลฐานข้อมูลที่ผูกกับแอปพลิเคชันเฉพาะ เขียน/ปรับแต่ง Stored Procedure และคิวรี SQL
Performance / Operations DBA : มุ่งติดตามเฝ้าระวังระบบ ปรับจูนแบบ Real-time และบำรุงรักษาให้พร้อมใช้ 24/7
7. ปัจจัยที่ใช้กำหนดสภาพแวดล้อมฐานข้อมูล
volatility : อัตราการเปลี่ยนแปลงแก้ไขข้อมูลในฐานข้อมูล
Data Size & Scale : ขนาดข้อมูลรวมและความเร็วในการขยายตัวของข้อมูล
Concurrent Users : จำนวนผู้ใช้งานและธุรกรรม (Transaction) ที่เข้าสู่ระบบพร้อมกัน
SLA & Availability : ข้อตกลงระดับบริการและมูลค่าความเสียหายหากเกิด Downtime
Security & Compliance : กฎหมายคุ้มครองข้อมูล (เช่น PDPA) และมาตรฐานความปลอดภัย
DBA Skill Readiness : ความรู้ความพร้อมในการจัดการปัญหาของทีมงาน
Backup Team : การเตรียมกำลังคนทดแทนเพื่อลดความเสี่ยงจากการพึ่งพาบุคคลเดียว (Key-man Risk)
8. ความปลอดภัยและการควบคุมสิทธิ์การใช้งาน (Database Security)
Authentication (การพิสูจน์ตัวตน) : กระบวนการยืนยันตัวตนของผู้ใช้งาน เช่น การใช้ Username/Password, การยืนยันตัวตนผ่าน OS (OS Authentication) หรือผ่านระบบคีย์ภายนอก
Authorization (การอนุญาตสิทธิ์) : การตรวจสอบสิทธิ์การใช้งานหลังผ่านด่านกรองตัวตนแล้ว ว่าผู้ใช้นี้มีสิทธิ์เรียกอ่านหรือจัดการข้อมูลใดบ้าง
ประเภทของสิทธิ์ (Privileges) :
System Privileges (สิทธิ์ระดับระบบ) : ควบคุมระดับกว้างของ DBMS เช่น CREATE SESSION (ล็อกอินเข้าระบบ), CREATE TABLE (สร้างตาราง), CREATE USER (สร้างบัญชีใหม่), DROP ANY TABLE (ลบตารางใดก็ได้) สิทธิ์กลุ่มนี้ถือว่าสูงมาก
Object Privileges (สิทธิ์ระดับวัตถุ) : ควบคุมเฉพาะบนออบเจกต์ฐานข้อมูล เช่น SELECT, INSERT, UPDATE, DELETE หรือ EXECUTE บนตารางหรือฟังก์ชันเฉพาะเจาะจง เช่น SELECT ON employees
9. บทบาทของ Roles ในการจัดการสิทธิ์
Role คือ กลุ่มของสิทธิ์ (Collection of Privileges) ที่แอดมินสร้างและรวบรวมสิทธิ์ประเภทต่างๆ เข้ามารวมศูนย์ไว้
ข้อดีของการใช้งาน Roles (Ease of Administration) :
ลดภาระงานของ DBA: แทนที่จะสั่ง GRANT/REVOKE สิทธิ์รายตัวให้พนักงานทีละคน ก็เพียงสร้าง Role แล้วแจก Role ให้พนักงานกลุ่มนั้นพร้อมกัน
แก้ไขสิทธิ์ง่าย: หากต้องการเพิ่มหรือยกเลิกสิทธิ์ของทั้งฝ่าย ก็เพียงดำเนินการที่ Role แค่บรรทัดเดียว จะส่งผลอัปเดตไปหาพนักงานทุกคนในกลุ่มโดยอัตโนมัติ
บริหารความปลอดภัยตามหน้าที่ (Least Privilege): เช่น จัดทำ finance_role, hr_role เพื่อให้สิทธิ์สอดคล้องตรงตามหน้าที่การทำงานจริงของบุคลากร
10. ส่วนประกอบของ 1 ฐานข้อมูล (Database Components)
ในระบบจัดการฐานข้อมูลระดับ Enterprise (เช่น Oracle) ทรัพยากรทั้งหมดจะแบ่งแยกออกเป็น 2 เลเยอร์ใหญ่:
Database (โครงสร้างทางกายภาพ - Physical Structure) : ส่วนของไฟล์ที่บันทึกจัดเก็บจริงและคงอยู่ถาวรในฮาร์ดดิสก์ (Disk Storage) ได้แก่:
Datafiles: ไฟล์จริงที่ใช้เก็บตารางข้อมูลดิบและดัชนี (Tables/Indexes)
Control Files: ไฟล์ควบคุมโครงสร้างและประวัติการซิงค์ระบบ ทำหน้าที่ระบุตำแหน่งไฟล์ประกอบการเปิดเครื่อง Instance
Redo Log Files: ไฟล์ประวัติคอยบันทึกทรานแซกชันที่มีการแก้ไขข้อมูล เพื่อรองรับกรณีไฟดับหรือเซิร์ฟเวอร์ล่ม
Instance (โครงสร้างทางตรรกะในแรม - Logical / Memory Structure) : ส่วนโปรแกรมที่ทำงานชั่วคราวอยู่ในหน่วยความจำแรม (RAM) ประกอบไปด้วยพื้นที่แรมแชร์อย่าง SGA (System Global Area) และกระบวนการทำงานหลังบ้าน Background Processes คอยรับคำสั่งและประสานงานเชื่อมต่อระหว่างยูสเซอร์ผู้ใช้กับไฟล์ Database บนฮาร์ดดิสก์
🏋️ โจทย์ซ้อมเขียนตอบเชิงวิเคราะห์ DBA Lecture ระดับข้อสอบ
ครูเตรียมแนวข้อสอบข้อเขียนเชิงทฤษฎีและการประยุกต์บริหารฐานข้อมูลมาให้ทบทวนครับ:
โจทย์ข้อที่ 1: การเลือกบทบาทผู้ดูแลระบบ (DBA Roles)
คำสั่งโจทย์: หากทีมพัฒนาแอปพลิเคชันต้องการเขียนและปรับปรุง Stored Procedure และปรับจูน SQL Query ในโมดูลบัญชีขององค์กร เพื่อให้ระบบประมวลผลได้รวดเร็วขึ้น ในฐานะผู้ดูแลระบบ คุณควรจัดสรรงานนี้ให้แก่ DBA บทบาทใด ระหว่าง System DBA, Database Architect หรือ Application DBA? พร้อมอธิบายเหตุผลประกอบ
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
ควรจัดสรรงานนี้ให้แก่ Application DBA ครับ เนื่องจากมีบทบาทหลักที่เน้นการทำงานร่วมกับนักพัฒนาซอฟต์แวร์และแอปพลิเคชันโดยตรง โดยมีความเชี่ยวชาญในการเขียนและปรับปรุงไวยากรณ์ SQL, การสร้างโมเดลความสัมพันธ์ (Schema), Stored Procedure, และ Triggers ให้ตอบสนองความต้องการทางธุรกิจของแอปพลิเคชันนั้นๆ
ในขณะที่ System DBA จะมุ่งเน้นการติดตั้งและบริหารแพลตฟอร์ม DBMS ในภาพรวมระดับกายภาพ (เช่น OS, Storage, Backup) และ Database Architect จะเน้นการวางแผนโครงสร้างสถาปัตยกรรมดาต้าเบสระดับภาพใหญ่เชิงตรรกะของทั้งองค์กรครับ
โจทย์ข้อที่ 2: การจัดการสิทธิ์ความปลอดภัยในระดับออบเจกต์ (Object Privileges)
คำสั่งโจทย์: พนักงานใหม่ฝ่ายการเงินต้องการสิทธิ์ในการดึงอ่านข้อมูลจากตาราง SALARIES เท่านั้น ห้ามแก้ไขหรือทำธุรกรรมใดๆ เพื่อป้องกันความลับรั่วไหล ในฐานะ DBA คุณควรปฏิบัติตามหลักการความปลอดภัยข้อใด และเลือกสั่งมอบสิทธิ์ (GRANT) ชนิดใดระหว่าง System Privilege และ Object Privilege?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
หลักการความปลอดภัย: ปฏิบัติตามหลักการ Least Privilege (สิทธิ์ขั้นต่ำสุดที่จำเป็น) โดยจำกัดให้เข้าถึงข้อมูลได้เฉพาะส่วนที่จำเป็นต่อการปฏิบัติงานจริงเท่านั้น
ชนิดสิทธิ์ที่ควร GRANT: ควรให้สิทธิ์เป็น Object Privilege โดยเฉพาะคำสั่ง SELECT ON SALARIES เพราะเป็นการคุมสิทธิ์เจาะจงกับตัวตารางนั้นๆ โดยตรง
ข้อควรระวัง: ไม่ควรให้ System Privilege (เช่น CREATE TABLE หรือ SELECT ANY TABLE) เด็ดขาด เนื่องจากสิทธิ์ระดับระบบจะเปิดกว้างและอาจทำให้พนักงานเข้าถึงหรือทำลายข้อมูลส่วนอื่นที่เป็นอันตรายได้ครับ
โจทย์ข้อที่ 3: ประสิทธิภาพในการจัดการความปลอดภัยด้วย Roles
คำสั่งโจทย์: องค์กรของคุณมีกลุ่มผู้ใช้ฝ่าย HR จำนวน 20 คน ซึ่งต้องได้รับสิทธิ์ในการ SELECT, INSERT, และ UPDATE บนตารางข้อมูลพนักงาน จงอธิบายขั้นตอนวิธีของ DBA ในการจัดการความปลอดภัยนี้โดยใช้ประโยชน์จาก Roles เพื่อให้ง่ายต่อการดูแลระบบ (Ease of Administration) และระบุความแตกต่างด้านภาระงานหากไม่ใช้งาน Role
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
ขั้นตอนปฏิบัติโดยใช้ Role:
DBA สั่งสร้าง Role ใหม่ เช่น CREATE ROLE hr_staff_role;
มอบสิทธิ์ระดับตารางให้กับ Role ตัวนี้: GRANT SELECT, INSERT, UPDATE ON employees TO hr_staff_role;
ผูกสิทธิ์ Role นี้ให้กับยูสเซอร์พนักงาน HR ทั้ง 20 บัญชีผู้ใช้งาน
การเปรียบเทียบภาระงาน:
หากไม่ใช้ Role: DBA ต้องพิมพ์คำสั่ง GRANT สิทธิ์ 3 สิทธิ์นี้ให้กับผู้ใช้ทีละคน แยกกัน 20 ครั้ง รวมคำสั่งทั้งหมด 3 * 20 = 60 คำสั่ง ซึ่งเสียเวลาและเสี่ยงต่อการผิดพลาด
หากใช้ Role: DBA รันคำสั่งรวมในการตั้งสิทธิ์เพียงแค่ 1 (สร้าง role) + 1 (ผูกสิทธิ์ให้ role) + 20 (แจก role ให้พนักงาน) = 22 คำสั่ง เท่านั้น และหากมีพนักงานลาออกหรือสิทธิ์มีการแก้ไข เช่น ต้องการเพิกถอนสิทธิ์ INSERT ก็เพียงแค่รันคำสั่งที่ตัว Role ครั้งเดียว (REVOKE) จะมีผลอัปเดตไปถึงพนักงานทั้ง 20 คนทันทีครับ
โจทย์ข้อที่ 4: ความแตกต่างระหว่าง Database และ Instance
คำสั่งโจทย์: ในฐานะแอดมินผู้ดูแลระบบ เมื่อมีคนพูดว่า "ฐานข้อมูลพังจนเครื่องเปิดไม่ขึ้น" และ "Instance ของระบบล่มไปเฉยๆ" สองสถานการณ์นี้มีความแตกต่างกันในแง่องค์ประกอบโครงสร้างของ DBMS อย่างไร?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
Instance ล่ม: หมายถึง ซอฟต์แวร์การประมวลผลบนแรม (SGA) และ background processes หยุดการทำงานชั่วคราว (เช่น เกิดไฟดับหรือระบบปฏิบัติการค้าง) แต่ข้อมูลไฟล์ทางกายภาพยังคงอยู่อย่างครบถ้วนสมบูรณ์ สามารถแก้ไขได้ง่ายๆ โดยการกดรัน Start Instance ใหม่ ระบบจะฟื้นตัวได้ในเวลาสั้น
Database พัง: หมายถึง เกิดความเสียหายกับไฟล์ข้อมูลจริงบนดิสก์เก็บข้อมูล (Physical Files) เช่น ฮาร์ดดิสก์เสีย ส่งผลให้ไฟล์ Datafiles หรือ Control Files หายไป สถานการณ์นี้รุนแรงกว่ามาก และจำเป็นต้องใช้กระบวนการกู้คืนข้อมูล (Recovery/Restore) จากแบ็กอัปภายนอกที่ DBA สำรองไว้ล่วงหน้าครับ
📝 จดบันทึกย่อบทเรียน
✓ บันทึกอัตโนมัติแล้ว
2 การสร้างสภาพแวดล้อมฐานข้อมูล (Database Environment)
1. ภาพรวมของ Database Environment
ประกอบด้วยองค์ประกอบทั้งหมดที่ทำให้ระบบพร้อมใช้งานจริงอย่างปลอดภัยและมีประสิทธิภาพ ไม่ใช่เพียงแค่ตัวซอฟต์แวร์ DBMS เท่านั้น:
DBMS Software , Hardware , OS , Storage , Network Infrastructure , และ กระบวนการ/ขั้นตอนปฏิบัติงาน (Procedures)
2. เกณฑ์การประเมินเลือกใช้ DBMS
OS & Platform Compatibility : การรองรับระบบปฏิบัติการ (OS) และสภาพแวดล้อม Cloud ขององค์กร
Benchmark & Scalability : ความสามารถในการเพิ่มขนาดเพื่อรองรับ Workload และการประมวลผล CPU/RAM
Tools & Ecosystem : ความสะดวกของเครื่องมืออำนวยความสะดวกในการทำ Backup, Monitoring, และ ETL
DBA Skill Readiness : ทักษะและความชำนาญของทีมงานที่มีต่อ DBMS แบรนด์นั้นๆ
TCO (Total Cost of Ownership) : ต้นทุนรวมทั้งหมด เช่น ค่า License ซอฟต์แวร์, ฮาร์ดแวร์, การบำรุงรักษา (MA), และค่า Migration
Vendor Support : นโยบายการออก Patch เพื่ออุดช่องโหว่ความปลอดภัย และระยะเวลาการสิ้นสุดการสนับสนุน (Support EOL)
3. ระดับของ DBMS (4 ระดับ)
Enterprise DBMS : เหมาะกับองค์กรขนาดใหญ่ที่ต้องการเก็บข้อมูลปริมาณมหาศาล (Terabytes) และรองรับ Concurrent สูงมาก
Departmental DBMS : ระดับแผนก/องค์กรกลาง เหมาะสมระหว่างต้นทุนกับประสิทธิภาพ
Personal DBMS : ใช้คนเดียว ติดตั้งส่วนบุคคล ไม่แนะนำให้ใช้ในระบบที่มีการประมวลผลพร้อมกันหลายคน (Multi-user)
Mobile / Embedded DBMS : เหมาะกับแอปพลิเคชันที่ต้องการทำงานแบบ Offline (เช่น POS หน้าร้าน) แล้วค่อยเชื่อมโยงซิงค์ข้อมูล (Synchronize) กลับฐานข้อมูลกลาง
4. DBMS Clustering
Shared-Disk : ทุก Node (Server) เชื่อมต่อเข้าประมวลผลที่ดิสก์เก็บข้อมูลตัวเดียวกัน ง่ายต่อการบริหารจัดการ แต่อาจเกิดปัญหาคอขวดอ่านเขียน (I/O Bottleneck)
Shared-Nothing : แต่ละ Node มี CPU, RAM และ Storage ของตัวเองโดยสมบูรณ์ ขยายตัวได้ดีเยี่ยม (High Scalability) แต่มีความซับซ้อนในการจัดการคิวรี
High Availability : เน้นระบบที่ไม่มีจุดล่มจุดเดียวและสามารถสลับใช้ระบบสำรองได้ทันที (Failover)
5. ผลเสียจาก DBMS Proliferation (การมี DBMS หลายแบรนด์เกินไปในองค์กร)
Support Burden : DBA ต้องแบกรับภาระและงานซ้ำซ้อนในการ Backup, Monitoring และจูนยี่ห้อที่ต่างกัน
Higher Costs : ค่า License ซ้ำซ้อน และเพิ่มต้นทุนในการจ้าง/ฝึกอบรมผู้เชี่ยวชาญหลายทาง
Inconsistent Standards : ความปลอดภัยและรอบการสำรองข้อมูลไม่สอดคล้องตามมาตรฐานเดียวกัน
Data Integration Issues : เกิดความยุ่งยากสูงในการย้าย (Migration) และเชื่อมโยงส่งผ่านข้อมูล
6. ปัจจัยจัดสรร Hardware & OS (ตามหลัก RAS: Reliability, Availability, Scalability)
CPU : ความเร็วและจำนวน Cores เพื่อรองรับ Concurrent Workload หนักๆ
Memory (RAM) : ขนาดที่พอดีสำหรับระบบและแคช (DBMS Buffer Pool, Data Cache) ป้องกันแรมไม่พอจนต้องสลับไปเขียน Disk
Storage System : ความเร็วในการอ่านเขียน (IOPS) และการทำ RAID รวมถึงกฎการแยกดิสก์เก็บ Data, Log, Backup
OS & Platform : ความเสถียร, การซัพพอร์ต Driver และนโยบายการ Patching OS
Manageability : การเตรียมการของทีมงานและเครื่องมือช่วยเฝ้าระวัง (Monitoring Tools)
7. Pre-Installation Checklist (รายการตรวจสอบก่อนติดตั้ง)
[x] OS & HW Readiness : ติดตั้งอัปเดต Patch OS, ตรวจเช็ก CPU/RAM ให้ตรงขั้นต่ำที่กำหนด
[x] Storage Separation : แยก Disk ในระดับกายภาพสำหรับเก็บ Data Files, Log Files, Temp Files, และ Backup Files ออกจากกัน
[x] Software & Drivers : จัดเตรียม Driver, DBA Tools และเครื่องมือแวดล้อมให้พร้อม
[x] Security & Access Control : ตรวจสอบบัญชีผู้ใช้งานระบบ (Service Accounts) และตั้งค่าปิดพอร์ตเครือข่ายที่ไม่จำเป็น
[x] Verification Plan : แผนทดสอบเขียนข้อมูล อ่านข้อมูล และสั่ง Backup/Restore
8. 5 องค์ประกอบของพื้นที่เก็บข้อมูลฐานข้อมูล (Storage Needs)
System Catalog / Data Dictionary : เก็บ Metadata โครงสร้างของตาราง ดัชนี สิทธิ์ และบัญชีผู้ใช้ระบบ
Transaction Log Files (Redo Log/WAL) : บันทึกข้อมูลประวัติการทำธุรกรรม เพื่อใช้สำหรับกู้คืนข้อมูล (Recovery & Audit)
Work / Temporary Files : ใช้ประมวลผลชั่วคราวเมื่อต้องการจัดการคำสั่งเรียงลำดับ (Sort, Merge) หรือ Hash Join ขนาดใหญ่
Control & Startup Files : เก็บข้อมูลสำคัญในการเปิดระบบ (Startup) และควบคุมความสมบูรณ์ของ Instance
Dump / Error Log Files : จัดเก็บไฟล์ Log แจ้งเตือนความเสียหายหรือข้อผิดพลาดของระบบสำหรับใช้ในการตรวจสอบหาข้อผิดพลาด
9. ขั้นตอน Configuration & Verification
Configuration : การระบุขนาดหน่วยความจำ (Memory), จำนวน Connection สูงสุด, Network Ports และขนาดของ Log ไฟล์ โดยต้องมีการลงบันทึกใน Change Log ทุกครั้งที่มีการแก้ไข
Verification (การทดสอบความถูกต้อง) :
ทดสอบว่า Service ของระบบฐานข้อมูลสามารถ Start ได้เรียบร้อย
ทดสอบให้ยูสเซอร์เชื่อมต่อผ่าน Network
ทดสอบรันคำสั่งเขียนและอ่านข้อมูลจริง (Write/Read Test)
ทดสอบสั่ง Backup และกู้คืนข้อมูล (Restore) สำเร็จลุล่วง
10. Version vs Release Management
Version Upgrade (Major) : เช่น Oracle 19c -> 23c หรือ PostgreSQL 15 -> 16 มีคุณสมบัติใหม่ๆ เข้ามาช่วยงาน แต่มีผลกระทบด้าน **ความเข้ากันได้ (Compatibility)** กับรหัสแอปพลิเคชันเดิมและเครื่องมือ ETL/Reporting
Release Upgrade (Minor / Patch) : เน้นแก้ไขบั๊กและช่องโหว่ความปลอดภัยด้านเทคนิคเป็นหลัก ผลกระทบต่ำกว่า
วงจรอัปเกรด (Upgrade Lifecycle) : 1. Assess (ประเมินความเข้ากันได้) -> 2. Test Plan (ทดสอบ Staging/เตรียม Backup-Rollback Plan) -> 3. Production Deploy (รันจริงใน Maintenance Window) -> 4. Verify (ตรวจสอบผลประสิทธิภาพหลังอัปเกรด)
11. Standards & Procedures
Standards : Naming Convention (มาตรฐานชื่อ DB/Table/Index), Access Control ( Least Privilege & Roles), Change Management (สิทธิ์การขอปรับปรุง Schema)
Procedures : Backup & Recovery (การทดสอบ Restore ประจำ), Incident Management ( Runbook เมื่อเกิดปัญหา), Documentation ( Data Dictionary ให้เป็นปัจจุบัน)
12. สถาปัตยกรรมหน่วยความจำและโปรเซสหลังบ้านของ Oracle (Oracle Database Architecture)
สถาปัตยกรรมของ Oracle Database แบ่งโครงสร้างหน่วยความจำออกเป็น 2 ส่วนหลัก:
A. System Global Area (SGA) - หน่วยความจำส่วนแชร์ (Shared Memory Area)
เป็นกลุ่มของโครงสร้างหน่วยความจำที่แชร์ใช้งานร่วมกันสำหรับโปรเซสของเซิร์ฟเวอร์และแบ็คกราวด์ทั้งหมด ทำงานเมื่อ Instance สตาร์ทตัวขึ้น ประกอบด้วยองค์ประกอบย่อยดังนี้:
Shared Pool : พื้นที่หน่วยความจำสำคัญที่แบ่งออกเป็น:
Library Cache : เก็บแผนการทำงาน (Execution Plan) และคำสั่ง SQL / PL-SQL ที่วิเคราะห์โครงสร้างแล้ว ป้องกันการวิเคราะห์ซ้ำ (Hard Parsing)
Data Dictionary Cache : เก็บแคชของข้อมูลพจนานุกรม เช่น โครงสร้างตาราง คอลัมน์ และสิทธิ์การใช้งานของผู้ใช้งาน
Database Buffer Cache : ใช้สำเนาบล็อกข้อมูลที่พึ่งอ่านขึ้นมาจากไฟล์ข้อมูลกายภาพ (Datafiles) เพื่อให้เมื่อผู้ใช้ขอข้อมูลแถวเดิมอีกครั้ง สามารถประมวลผลดึงจากแรมได้รวดเร็วทันทีโดยไม่ต้องอ่านฮาร์ดดิสก์
Redo Log Buffer : พื้นที่พักจัดเก็บการบันทึกประวัติการแก้ไขข้อมูล (Redo entries) ทุกครั้งที่มีการรันธุรกรรม DML เพื่อเตรียมเขียนลงในไฟล์ล็อกสำหรับใช้กู้ภัยข้อมูล
Large Pool : พื้นที่หน่วยความจำเสริมอิสระสำหรับกระบวนการขนาดใหญ่ เช่น การสำรองและกู้คืนด้วย RMAN หรือการจัดการคิวของเซิร์ฟเวอร์แบบแชร์ (Shared Server operations)
Java Pool : พื้นที่เก็บแคชคำสั่งสำหรับรันโปรแกรมภาษา Java ภายในเครื่องฐานข้อมูล
B. Program Global Area (PGA) - หน่วยความจำส่วนบุคคล (Private Memory Area)
เป็นพื้นที่หน่วยความจำที่ถูกจองแยกเฉพาะสำหรับแต่ละ Server Process (เซสชันเฉพาะของแต่ละผู้ใช้งาน) ไม่เปิดแชร์ให้กับยูสเซอร์คนอื่น
ใช้จัดเก็บบันทึกข้อมูลสถานะส่วนตัว เช่น ตัวแปรในคำสั่ง PL/SQL, พื้นที่จัดการการเรียงลำดับข้อมูล (Sort Area) และตารางดึงข้อมูลชั่วคราว
13. กระบวนการประมวลผลหลังบ้าน (Background Processes ใน Oracle)
กลุ่มโปรเซสการทำงานเบื้องหลังที่ทำหน้าที่ควบคุมการทำงานของเครื่องเซิร์ฟเวอร์ฐานข้อมูลให้มีประสิทธิภาพและปลอดภัย:
DBWn (Database Writer) : สแกน Database Buffer Cache และทำหน้าที่เขียนบล็อกข้อมูลที่มีการเปลี่ยนแปลง (Dirty Buffers) ลงดิสก์เก็บไฟล์ข้อมูลจริง (Datafiles) ในจังหวะที่เหมาะสมแบบ Asynchronous
LGWR (Log Writer) : ทำหน้าที่คัดลอกข้อมูลการทำธุรกรรมจาก Redo Log Buffer ในหน่วยความจำ เขียนลงในไฟล์ Redo Log Files บนดิสก์อย่างรวดเร็วทันทีเมื่อ:
ผู้ใช้งานสั่งบันทึกธุรกรรม (COMMIT)
ข้อมูลใน Redo Log Buffer เต็มเกิน 1 ใน 3
ก่อนที่โปรเซส DBWn จะเขียนบล็อกสกปรกกลับลง Datafile
CKPT (Checkpoint) : ควบคุมจังหวะเช็คพอยต์การซิงค์ข้อมูล โดยสั่งการให้ DBWn เขียนข้อมูลแรมลงดิสก์ และบันทึกหมายเลขลำดับข้อมูล (System Change Number - SCN) ล่าสุดกลับไปเก็บไว้ใน Control Files และ Header ของ Datafiles เพื่อทำเครื่องหมายระดับที่บันทึกข้อมูลเรียบร้อยแล้ว
SMON (System Monitor) : ดูแลความเรียบร้อยระดับตัวระบบ Instance เช่น การทำงานกู้คืน Instance อัตโนมัติเมื่อระบบไฟฟ้าขัดข้อง (Instance Recovery) และจัดการคืนพื้นที่ว่างชั่วคราว (Temporary Segment) คืนสู่ระบบ
PMON (Process Monitor) : จัดการเฝ้าระวังโปรเซสของผู้ใช้งานแต่ละคน หากตรวจพบการเชื่อมต่อของเซสชันที่ขาดหายไปอย่างกะทันหัน PMON จะดำเนินการ rollback ธุรกรรมที่ยังค้างอยู่ทิ้ง เคลียร์พื้นที่แรม (PGA) และปลดล็อกตาราง (Locks) คืนให้ผู้ใช้อื่นเข้าทำงานต่อ
ARCn (Archiver Process) : ทำงานคัดลอกโคลนข้อมูลจากไฟล์ Redo Log ที่ใช้งานวนชนรอบเต็มแล้ว ไปสำรองเก็บเป็นไฟล์ Archive Log เพื่อใช้ในความปลอดภัยระบบ Hot Backup (รันได้เฉพาะเมื่อเปิดโหมด ARCHIVELOG)
14. ความสัมพันธ์โครงสร้างเชิงกายภาพและตรรกะ (Physical vs Logical Structures)
ประเภท
องค์ประกอบโครงสร้าง
ลักษณะการทำงานและความเชื่อมโยง
Physical (กายภาพจริง)
Datafiles, Control files, Redo log files
เป็นไฟล์ที่บันทึกถาวรลงในสื่อดิสก์ สามารถตรวจสอบขนาดและชื่อไฟล์ได้ผ่าน OS หรือ File Explorer
Logical (เชิงตรรกะในระบบ)
Tablespaces, Segments, Extents, Data Blocks
เป็นโครงสร้างจำลองที่ DBMS จัดทำขึ้นเพื่อใช้จัดการแบ่งสัดส่วนเนื้อที่ โดย Tablespace เป็นตัวรวมกลุ่มของไฟล์ Datafile, Segment คือออบเจกต์ตาราง/ดัชนี, Extent คือบล็อกต่อเนื่อง, และ Data Block คือขนาดหน่วยเก็บเล็กสุด
Schema (สคีมา)
Tables, Views, Indexes, Sequences...
ขอบเขตการครอบครองอ็อบเจกต์ทั้งหมดของบัญชีผู้ใช้งาน 1 ราย ข้อมูลตารางใน Schema สามารถเก็บกระจายลง Tablespace ต่างๆ ได้อิสระ
🏋️ โจทย์ซ้อมเขียนตอบเชิงวิเคราะห์ DBA Lecture ระดับข้อสอบ
ครูเตรียมแนวข้อสอบข้อเขียนเชิงทฤษฎีและการประยุกต์บริหารฐานข้อมูลมาให้ทบทวนครับ:
โจทย์ข้อที่ 1: การทำงานของ Shared Pool และ Database Buffer Cache
คำสั่งโจทย์: พนักงานรันคำสั่งคิวรี SELECT * FROM employees WHERE employee_id = 100; ในครั้งแรกพบว่าใช้เวลานานเกือบ 2 วินาที แต่เมื่อกดคิวรีเดิมซ้ำในวินาทีถัดไป กลับใช้เวลาเพียงไม่ถึง 0.05 วินาที จงอธิบายว่าเกิดจากการทำงานขององค์ประกอบใดใน SGA ของ Oracle บ้าง?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
เกิดจากการแคชข้อมูลของ 2 องค์ประกอบหลักใน SGA ทำงานประสานกันดังนี้ครับลูกศิษย์:
Shared Pool (Library Cache): ในการคิวรีครั้งแรก Oracle ต้องทำการแยกแยะความถูกต้องเชิงโครงสร้าง และวิเคราะห์เส้นทางการดึงข้อมูล (เรียกว่า Hard Parsing) แล้วเก็บบันทึกคำสั่งและแผนคำนวณ (Execution Plan) ไว้ใน Library Cache เมื่อส่งคำสั่งเดิมเข้ามาครั้งที่สอง ระบบจะนำแผนเดิมมารันต่อได้ทันที (เรียกว่า Soft Parsing) ช่วยลดขั้นตอนการคอมไพล์คิวรี
Database Buffer Cache: ในครั้งแรก ระบบจำเป็นต้องดึงบล็อกข้อมูลจากฮาร์ดดิสก์จริง (Physical Datafiles) ขึ้นมาอ่านในหน่วยความจำ RAM และสำเนาเก็บไว้ใน Buffer Cache เมื่อดึงข้อมูลตัวเดิมในรอบสอง ระบบจะสามารถคัดลอกจาก RAM ไปแสดงผลได้ทันทีโดยไม่ต้องเสียเวลาไปอ้างอิง I/O บนฮาร์ดดิสก์ที่ทำงานช้ากว่ามากครับ
โจทย์ข้อที่ 2: ความแตกต่างที่สำคัญระหว่าง SGA และ PGA
คำสั่งโจทย์: ในฐานะ DBA จงอธิบายความแตกต่างในการจัดสรรพื้นที่ใช้งานและสิทธิ์การเข้าถึงข้อมูลระหว่างพื้นที่หน่วยความจำ SGA และ PGA ให้แก่นักพัฒนาในทีมเข้าใจ
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
SGA (System Global Area): เป็นพื้นที่หน่วยความจำร่วมระดับระบบ (Shared Memory) ที่ถูกจองขึ้นมาตั้งแต่เปิด Instance ทุกๆ เซิร์ฟเวอร์โปรเซสและกระบวนการทำงานหลังบ้านร่วมใช้งาน และแบ่งปันข้อมูลกันได้ เช่น บล็อกข้อมูลแคช หรือคำสั่ง SQL ที่ใช้ร่วมกัน
PGA (Program Global Area): เป็นพื้นที่หน่วยความจำส่วนบุคคลระดับเซสชัน (Private Memory) ถูกจัดสรรแยกออกไปเป็นเอกเทศให้กับแต่ละ Server Process ของผู้ใช้งานแต่ละคนโดยเฉพาะ เพื่อเก็บประวัติการรันและตัวแปรของยูสเซอร์นั้นๆ โดยยูสเซอร์ผู้อื่นหรือโปรเซสภายนอกจะไม่สามารถเข้าถึงหน่วยความจำส่วนตัวของ PGA คนนี้ได้เลยครับ
โจทย์ข้อที่ 3: บทบาทและเงื่อนไขการทำงานของ LGWR vs DBWn
คำสั่งโจทย์: ในระบบฐานข้อมูลของ Oracle เมื่อผู้ใช้งานกดรันคำสั่งแก้ไขและ COMMIT ข้อมูล ทำไมระบบจึงสามารถรับประกันความปลอดภัยของข้อมูลได้ทันที ทั้งๆ ที่ข้อมูลตารางจริงอาจยังไม่ถูกเขียนกลับลงไฟล์ Datafiles บนดิสก์? จงระบุโปรเซสเบื้องหลังที่เป็นตัวขับเคลื่อนเหตุการณ์นี้
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
สถานการณ์นี้เป็นไปตามหลักการ Write-Ahead Logging ของระบบจัดการฐานข้อมูลองค์กร:
เมื่อยูสเซอร์ส่งคำสั่ง COMMIT โปรเซส LGWR (Log Writer) จะทำหน้าที่เขียนบันทึกประวัติการเปลี่ยนแปลงทั้งหมดจากหน่วยความจำชั่วคราว Redo Log Buffer ลงสู่ไฟล์ Redo Log Files บนฮาร์ดดิสก์ทันทีก่อนกระบวนการอื่น ซึ่งเป็นการเขียนไฟล์แบบต่อท้ายต่อเนื่อง (Sequential Write) จึงรวดเร็วมาก
ส่วนข้อมูลตารางจริงใน Database Buffer Cache จะถูกระบุสถานะเป็น Dirty Buffers (ข้อมูลสกปรกที่ยังไม่ซิงค์) ซึ่งจะรอให้โปรเซส DBWn (Database Writer) ทยอยรันเขียนลงไฟล์จริง Datafiles แบบไม่ประสานเวลา (Asynchronous/Lazy Write) ในภายหลังเพื่อไม่ให้รบกวนความเร็วของผู้ใช้งาน
ดังนั้น ข้อมูลจึงปลอดภัยแล้วเพราะถ้าหากเกิดไฟดับหลัง COMMIT ระบบจะสามารถย้อนอ่านไฟล์ Redo Log มาเขียนกู้ข้อมูลขึ้นใหม่ได้ (Roll forward) เสมอครับ
โจทย์ข้อที่ 4: การทำงานกู้คืนของ PMON และ SMON
คำสั่งโจทย์: หากไฟดับกะทันหันส่งผลให้ยูสเซอร์ที่กำลังรันคำสั่งแก้ไขตารางค้างคาอยู่โดนตัดสายการทำงานหลุดออกจากเซิร์ฟเวอร์ จงอธิบายบทบาทการทำงานที่ต่างกันระหว่างโปรเซส PMON และ SMON ในการจัดการความเสถียรของระบบ
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
PMON (Process Monitor): จะเฝ้าคอยเคลียร์ปัญหาเซสชันของผู้ใช้ที่พังหรือถูกตัดขาดการทำงาน (User Process Failure) โดยจะทำการยกเลิก (Rollback) ทรานแซกชันที่ค้างอยู่ ปลดล็อกตาราง (Locks) ที่ผู้ใช้ลือคุมไว้ และเคลียร์หน่วยความจำ PGA เพื่อคืนทรัพยากรให้ระบบพร้อมบริการผู้อื่น
SMON (System Monitor): จะทำหน้าที่กู้คืนความเสถียรในระดับระบบ (Instance Recovery) เมื่อเกิดเครื่องล่มหรือไฟดับทั้งเซิร์ฟเวอร์ โดยเมื่อระบบเริ่มบูท (Start Instance) ขึ้นใหม่ SMON จะอ่านไฟล์ Redo Log เพื่อรันคำสั่งที่ commit ไปแล้ว (Roll forward) และยกเลิกทรานแซกชันที่ยังไม่สำเร็จ (Rollback/Undo) เพื่อให้สถานะข้อมูลของฐานข้อมูลทั้งหมดสอดคล้องถูกต้องเหมือนเดิมครับ
📝 จดบันทึกย่อบทเรียน
✓ บันทึกอัตโนมัติแล้ว
3 การบริหารการเปลี่ยนแปลงฐานข้อมูล (Database Change Management)
1. ทำไมการเปลี่ยนแปลงฐานข้อมูลถึงยากและเสี่ยง?
ในงานของ DBA การปรับโครงสร้างฐานข้อมูล (Database Schema) บนระบบจริงที่กำลังรันอยู่ (Production Environment) มีความเสี่ยงสูงกว่าการเปลี่ยนโค้ดแอปพลิเคชันทั่วไป เพราะ:
Data Integrity (ความคงสภาพข้อมูล): ข้อมูลเดิมต้องไม่สูญหาย เสียหาย หรือเกิดความไม่สอดคล้อง
Schema Evolution (การวิวัฒนาการโครงร่าง): เมื่อธุรกิจเติบโต ตารางต้องมีการปรับปรุงโครงสร้าง (เช่น เพิ่มคอลัมน์ใหม่, เปลี่ยน Data Type, ผูก Constraints) ซึ่งอาจขัดแย้งกับแอปพลิเคชันเวอร์ชันเก่า
Downtime (เวลาที่ระบบหยุดทำงาน): การทำโครงสร้างใหม่อาจทำให้ตารางล็อกยาว ส่งผลให้แอปพลิเคชันรันต่อไม่ได้และลูกค้าเข้าใช้งานไม่ได้
2. วิกฤตคำสั่ง ALTER TABLE และเทคนิคการสลับตาราง (Table Swapping) - ออกสอบอัตนัยวิเคราะห์!
การใช้คำสั่ง ALTER TABLE บนโปรดักชันที่มีข้อมูลขนาดใหญ่หลายสิบล้านแถว (Large Database) มีความอันตรายสูง:
⚠️ วิกฤตล็อกตาราง (Exclusive Lock Risk):
คำสั่งปรับโครงสร้างเช่น ALTER TABLE MODIFY(column_name DataType) จะทำการขอสิทธิ์ Exclusive Lock (ล็อกผูกขาด) บนตารางนั้น
➜ ผลลัพธ์: ระบบจะบล็อกทั้งคำสั่งอ่าน (SELECT) และเขียน (INSERT/UPDATE) ของแอปพลิเคชันทั้งหมด จนกว่าคำสั่งจะรันเสร็จสิ้น ส่งผลให้เกิดปัญหา Connection Timeout (แอปพลิเคชันค้างคีย์งานไม่ได้) และระบบล่มในที่สุด
💡 ทางออกระดับมือโปร: เทคนิค Table Swapping (การทำสำเนาสลับชื่อ)
ใช้เพื่อความปลอดภัยในตารางที่มีปริมาณทรานแซกชันหนาแน่น:
สร้างตารางใหม่ (New Table): ประกาศตารางที่มีโครงสร้างใหม่แกะกล่องเสร็จสรรพ พร้อมดัชนีและคอนสเตรนต์ เช่น CREATE TABLE temp_employees (...)
ย้ายข้อมูล (Data Migration): ย้ายข้อมูลจากตารางเดิมมาตารางใหม่ในลักษณะแบตช์ (Batching) หรือแบ่งสัดส่วนทีละน้อยเพื่อป้องกันคอขวดระบบ
สลับชื่อ (Swapping): ทำการเปลี่ยนชื่อสลับที่กันอย่างรวดเร็ว (เสร็จในหลักมิลลิวินาที):
- DROP TABLE employees; (หรือเปลี่ยนชื่อเก็บเป็นประวัติการสำรองข้อมูล)
- RENAME temp_employees TO employees;
3. ประเภทการสำรองและกู้คืนข้อมูล (Database Backup & Recovery Types)
DBA มีหน้าที่วางแผนการสำรองข้อมูลให้สอดคล้องกับงบประมาณและทรัพยากรระบบ:
มิติการวิเคราะห์
Hot Backup (สำรองแบบออนไลน์)
Cold Backup (สำรองแบบออฟไลน์)
สถานะการทำงาน
ทำขณะที่ฐานข้อมูล **กำลังรันและให้บริการลูกค้าอยู่**
ทำขณะที่ทำการ **ชัตดาวน์ฐานข้อมูล (Shutdown DB)** สนิท
โหมดการรัน
ต้องการโหมด **ARCHIVELOG** เพื่อซิงค์ไฟล์ Log ตลอดเวลา
ไม่ต้องใช้โหมดพิเศษใดๆ (ทำได้ง่ายระดับไฟล์ระบบ)
ผลกระทบต่อธุรกิจ
ศูนย์ Downtime: เหมาะกับระบบที่เปิด 24/7 เช่น แบงก์กิ้ง อีคอมเมิร์ซ
มี Downtime: ต้องปิดเซิร์ฟเวอร์ชั่วคราวในช่วงทำระบบสำรอง
📦 การจัดกลุ่มสำรองข้อมูลตามลักษณะความแตกต่าง (Backup Methods):
Full Backup: สำรองข้อมูลไฟล์ทั้งหมดในระบบตารางแบบ 100% ปลอดภัยที่สุด แต่กินพื้นที่และใช้เวลานานสูงสุด
Incremental Backup: สำรองเฉพาะไฟล์ข้อมูลที่มีการแก้ไข **หลังจากทำการสำรองข้อมูลรอบล่าสุด (ไม่ว่ารอบนั้นจะเป็นแบบใด)** ช่วยประหยัดพื้นที่คลังสำรอง
Differential Backup: สำรองเฉพาะไฟล์ข้อมูลที่มีการแก้ไข **หลังจากทำการ Full Backup ล่าสุดเท่านั้น** ทำให้ข้อมูลสะสมบวมขึ้นเรื่อยๆ แต่กู้คืนได้เร็วกว่าแบบแรก
4. กระบวนการควบคุมการเปลี่ยนแปลง (Change Control Process)
ก่อนที่ DBA จะทำการรันสคริปต์ใดๆ บนเซิร์ฟเวอร์จริง ต้องผ่านกระบวนการคุมความปลอดภัยสากล:
RFC (Request for Change): แบบฟอร์มใบคำร้องขอเปลี่ยนแปลงโครงสร้าง ระบุเหตุผล แผนพัฒนา และผู้ดำเนินการ
CAB (Change Advisory Board): คณะกรรมการผู้เชี่ยวชาญร่วมตรวจสอบความเสี่ยง ผลกระทบ และอนุมัติใบคำร้อง
Rollback Plan (แผนย้อนกลับ - จุดเน้นออกข้อสอบเขียน): แผนระบุคำสั่งแก้ไขย้อนกลับแบบทีละสเต็ป (Step-by-step) อย่างละเอียดชัดเจน เพื่อบังคับรันย้อนคืนหากเกิดปัญหาแอปพลิเคชันค้างหลังแก้ไข
🏋️ โจทย์ซ้อมเขียนตอบเชิงวิเคราะห์ DBA Lecture ระดับข้อสอบ
ครูเตรียมแนวข้อสอบข้อเขียนเชิงทฤษฎีและการประยุกต์บริหารฐานข้อมูลมาให้ทบทวนครับ:
โจทย์ข้อที่ 1: วิเคราะห์และแก้ไขปัญหาล็อกตารางบนระบบจริง
คำสั่งโจทย์: ระบบฐานข้อมูลซื้อขายสินค้าขนาดใหญ่มีคนรัน SELECT/INSERT ตลอด 24 ชั่วโมง วันหนึ่ง DBA ต้องการแก้ไขชนิดคอลัมน์เงินเดือนจาก NUMBER(6) เป็น NUMBER(8)
1) หาก DBA ใช้คำสั่ง ALTER TABLE employees MODIFY (salary NUMBER(8)); ตรงๆ บนระบบจริง จะเกิดผลกระทบใด?
2) จงอธิบายขั้นตอนวิธีแก้ไขป้องกันปัญหานี้
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
ผลกระทบที่เกิดขึ้น: เกิดปัญหา Exclusive Lock บนตาราง ระบบจะบล็อกคำสั่งสืบค้นและทำรายการของพนักงานขายทุกคนที่พยายามเข้าถึงตารางนี้ ส่งผลให้ระบบทรานแซกชันหน้าร้านค้าง และทำให้เว็บขึ้น Connection Timeout ล่มในที่สุดเนื่องจากตารางถูกล็อกเป็นเวลานานตามขนาดข้อมูล
ขั้นตอนการแก้ไข (Table Swapping):
- 1. สร้างตารางสำรองชั่วคราวใบใหม่ที่มีโครงสร้างเสร็จสรรพ เช่น CREATE TABLE temp_employees (id, name, salary NUMBER(8), ...);
- 2. ทำการย้ายคัดลอกข้อมูลจากตารางเดิมเข้าตารางใหม่แบบแบตช์ (Batch Migration) นอกชั่วโมงเร่งด่วนเพื่อไม่ให้ขัดขวางแรมระบบ
- 3. นัดหมายช่วงเวลาบำรุงรักษาระบบ (Maintenance Window) ทำการ DROP หรือ RENAME ตารางเก่าเก็บไว้เป็นสำรองข้อมูล และ RENAME ตารางชั่วคราวสลับขึ้นมาแทนที่แบบรวดเร็ว
โจทย์ข้อที่ 2: วางแผนการสำรองข้อมูลสำหรับระบบโรงพยาบาล 24/7
คำสั่งโจทย์: โรงพยาบาลใหญ่แห่งหนึ่งรันระบบบันทึกประวัติคนไข้ตลอด 24 ชั่วโมง มีทรานแซกชันเข้าตลอดวินาทีและไม่สามารถมี Downtime ได้เลย
1) ในฐานะ DBA คุณควรจัดทำแผนการสำรองข้อมูลระบบแบบใดระหว่าง Hot Backup และ Cold Backup? เพราะเหตุใด?
2) จำเป็นต้องตั้งค่าโหมดการทำงานของฐานข้อมูลเป็นโหมดใด?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
เลือกทำ Hot Backup (Online Backup): เนื่องจากระบบดูแลชีวิตคนไข้ไม่สามารถทำการชัตดาวน์ปิดเครื่องฐานข้อมูลเพื่อทำสำเนาได้ (ห้ามเกิด Downtime) ระบบต้องพร้อมอ่าน/เขียนตลอดเวลา การเลือกทำ Hot Backup จะทำให้การสำรองข้อมูลทำได้คู่ขนานไปกับการให้บริการตามปกติ
โหมดที่จำเป็นต้องใช้: ต้องปรับตั้งค่าฐานข้อมูลให้ทำงานอยู่ในโหมด ARCHIVELOG เพื่อให้ระบบทำการสำรองเก็บไฟล์บันทึกการเปลี่ยนแปลง (Redo Logs) ตลอดเวลา ซึ่งจำเป็นสำหรับฟังก์ชันการเขียนกู้คืนข้อมูลของ Hot Backup
โจทย์ข้อที่ 3: ออกแบบแผนย้อนกลับ (Rollback Plan) ในเอกสาร RFC
คำสั่งโจทย์: DBA มีหน้าที่ทำการเพิ่มตารางข้อมูลใหม่ชื่อ MEMBER_TIERS ลงบนระบบโปรดักชัน แต่ต้องเขียนระบุ "แผนย้อนกลับ (Rollback Plan)" แนบในคำร้องขอเปลี่ยนแปลง (RFC) ด้วย
จงเขียนคำสั่ง SQL สำหรับแผนย้อนกลับนี้เพื่อป้องกันความเสี่ยง
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
ในแผนย้อนกลับ (Rollback Plan) ต้องบอกขั้นตอนลบสิ่งที่เพิ่งติดตั้งให้ออกจากระบบคืนสถานะเดิมอย่างปลอดภัยทีละบรรทัด:
-- Rollback Plan Step 1: ลบตารางที่พึ่งติดตั้งใหม่ออกจากระบบหลัก
DROP TABLE MEMBER_TIERS CASCADE CONSTRAINTS;
-- Rollback Plan Step 2: คืนสิทธิ์การเข้าถึงของผู้ใช้งานระบบ (หากมีการ revoke ชั่วคราวก่อนหน้านี้)
-- (ตรวจสอบและสับสวิตช์เปิดใช้ triggers / constraints เดิมที่ถูกปิดไว้ชั่วคราวระหว่างดีพลอย)
📝 บันทึกส่วนตัว — บทที่ 3
✓ บันทึกอัตโนมัติแล้ว
4 ความพร้อมใช้งานของฐานข้อมูล (Database Availability)
1. "The Nines" Benchmark (ระดับความพร้อมใช้รายปี)
ระดับเปอร์เซ็นต์
Downtime ต่อปี
กลุ่มธุรกิจและตัวอย่างการใช้งาน
99.0% (Two Nines)
~ 3 วัน 15 ชั่วโมง
ระบบภายในที่ไม่วิกฤต เช่น บันทึกเวลาเข้าออก หรือคลังเอกสารทดลอง
99.9% (Three Nines)
~ 8 ชั่วโมง 46 นาที
ระบบ ERP ภายในบริษัท หรือระบบสั่งงานหลังบ้านทั่วไป
99.99% (Four Nines)
~ 52 นาที 36 วินาที
ระบบวิกฤตเชิงพาณิชย์ เช่น ชำระเงิน (POS Gateway) หรือแอปจองสายการบิน
99.999% (Five Nines)
~ 5 นาที 15 วินาที
ระบบโอนเงินหลักของธนาคารพาณิชย์ หรือศูนย์ประมวลผลตลาดหลักทรัพย์
2. 4 ด้านของ Availability (4 Pillars)
Reliability : ให้บริการต่อเนื่องอย่างเสถียร ไม่มีบั๊กหรือจุดล่มจุดเดียว (Fault Tolerance)
Recoverability : กู้ระบบกลับมาให้บริการได้อย่างรวดเร็วและถูกต้องสมบูรณ์หลังเกิดเหตุล่ม
Serviceability : ตรวจพบ วินิจฉัย และแก้ไขปัญหาข้อผิดพลาดได้อย่างมีประสิทธิภาพรวดเร็ว
Manageability : บริหารจัดการเปลี่ยนผ่าน ลง Patching และบำรุงรักษาโดยเป็นระบบและมีผลกระทบต่ำสุด
3. ต้นทุนของ Downtime (4 ประเภท)
ต้นทุนทางตรง (Direct Costs) : รายได้ที่หดหายทันที ค่าปรับตามสัญญา SLA และค่าจ้างทีมงานมาช่วยกู้ภัยระบบ
ต้นทุนทางอ้อม (Indirect Costs) : ลูกค้าสูญเสียความเชื่อมั่น (Churn), พนักงานค้างงาน และชื่อเสียงแบรนด์/ราคาหุ้นเสียหาย
ต้นทุนการสะสาง (Catch-up Costs) : การคีย์ข้อมูลย้อนหลังจากกระดาษ, การทำกระทบยอด (Reconciliation) ตรวจความถูกต้องหลังฟื้นตัว
ต้นทุนทางกฎหมาย (Legal Costs) : การถูกยื่นฟ้องร้องดำเนินคดี หรือค่าปรับจากการละเมิดกฎหมายคุ้มครองข้อมูลส่วนบุคคล
4. Planned vs Unplanned Downtime (เวลาหยุดทำงานที่วางแผนไว้ vs ที่ไม่ได้คาดคิด)
การบริหารจัดการระบบฐานข้อมูลของ DBA ต้องประเมินความพร้อมใช้งานตามลักษณะการปิดตัวของระบบ:
Planned Downtime (เวลาปิดระบบตามแผนล่วงหน้า) : กิจกรรมที่ DBA คาดหมายและแจ้งเตือนผู้ใช้ไว้ล่วงหน้าเพื่อบำรุงรักษา
ตัวอย่าง: การติดตั้ง OS patches, การอัปเกรดเวอร์ชันฐานข้อมูล (DBMS Upgrade), การเปลี่ยนถ่ายสลับอุปกรณ์ฮาร์ดแวร์เซิร์ฟเวอร์, การปรับโครงสร้าง Schema ตารางหลัก
การลดผลกระทบ: กำหนดช่วงบำรุงรักษานอกเวลาทำการ (Maintenance Window), ทำการสำรองข้อมูลล่วงหน้า 100%, หรือใช้ระบบจัดสรรคลัสเตอร์รองรับ
Unplanned Downtime (เวลาล่มโดยไม่ได้คาดคิด) : เหตุการณ์วิกฤตที่ทำให้ระบบล้มเหลวโดยฉับพลัน ส่งผลกระทบเชิงลบต่อธุรกิจทันที
ตัวอย่าง: อุปกรณ์ฮาร์ดแวร์เสียหาย (เช่น ดิสก์เสีย, แหล่งจ่ายไฟพัง), ระบบซอฟต์แวร์มีบั๊กรุนแรงค้างสะสม, การโจมตีทางไซเบอร์, เหตุการณ์ภัยธรรมชาติ/ไฟดับทั้งไซต์งาน, หรือความผิดพลาดจากการสั่งคำสั่งทำลายของมนุษย์ (Human Error)
การลดผลกระทบ: วางระบบสำรองแบบพร้อมสลับใช้อัตโนมัติ (Failover), การกำหนดเป้าหมายกู้ภัย RTO/RPO ชัดเจน, และจัดเก็บข้อมูลบน RAID หรือ Data Replication
5. การตั้งเกณฑ์ RTO และ RPO
RTO (Recovery Time Objective) : ระยะเวลา **สูงสุด** ที่ยอมให้ระบบหยุดให้บริการ (วัดเป็น **เวลาในการกู้**) เช่น POS RTO < 30 นาที
RPO (Recovery Point Objective) : ปริมาณข้อมูลธุรกรรมล่าสุด **สูงสุด** ที่ยินยอมให้หายไปได้เมื่อระบบพัง (วัดเป็น **เวลาของข้อมูลที่ยอมหาย**) เช่น POS RPO < 5 นาที
6. โซลิวชันฮาร์ดแวร์ดิสก์สำรอง (RAID Levels)
ระดับ RAID
ลักษณะการทำงาน
ความเร็ว / ความปลอดภัย
การนำมาใช้งานใน DB
RAID 0
Block Striping กระจายข้อมูลลงดิสก์ทุกลูก
เร็วมาก / ข้อมูลไม่มี Redundancy เลย ดิสก์เสียลูกเดียวข้อมูลพังหมด
เก็บข้อมูลชั่วคราว Temp space หรือ Scratch files
RAID 1
Block Mirroring โคลนข้อมูลขนานคู่
เขียนปานกลาง อ่านดี / สูญเสียพื้นที่ 50% ทนดิสก์เสียได้ 1 ลูก
เก็บไฟล์ทรานแซกชันล็อก (Logs) และ Control Files
RAID 5
Distributed Parity กระจายรหัสช่วยกู้
อ่านเร็ว เขียนช้า / ทนดิสก์เสีย 1 ลูก เกิด Write Penalty (4 I/O)
เน้นการอ่านเป็นหลัก (Read-Heavy), Data Warehouse
RAID 6
Double Distributed Parity กระจายรหัสช่วยกู้สองชุดขนานกัน
อ่านเร็วมาก เขียนช้ากว่า RAID 5 / สูญเสียพื้นที่ดิสก์เท่ากับ 2 ลูก สามารถทนทานต่อเหตุการณ์ดิสก์เสียหายพร้อมกันได้สูงสุดถึง 2 ลูก
เก็บข้อมูลที่สำคัญปานกลางถึงสูง เน้นความน่าเชื่อถือของการอ่านข้อมูล เช่น ระบบประวัติเก็บเอกสารอ้างอิง
RAID 10 (1+0)
Mirror + Stripe รวมความเร็วและความทน
เร็วและปลอดภัยที่สุด / พื้นที่หาย 50% ทนดิสก์เสียได้สูงสุด 50%
เหมาะสมที่สุดสำหรับ Data & Log ในฐานข้อมูล Production
7. โซลูชัน High Availability ของ Oracle Database
Oracle RAC (Real Application Clusters) : สถาปัตยกรรมแบบ Shared-Disk Clustering ทำงานแบบ Active-Active ส่งมอบความเร็วผ่าน Cache Fusion
Oracle Data Guard : การส่งถ่ายข้อมูล Redo Logs ไปซิงค์เก็บที่ศูนย์ Standby DR Site ช่วยป้องกันภัยพิบัติและย้ายระบบออกรายงาน
Flashback Technology : กู้คืนข้อมูลอย่างรวดเร็วระดับ Logical (เช่น Flashback Drop กู้ตาราง, Flashback Query ดูประวัติอดีต) โดยไม่ต้อง Restore
RMAN & Fast Recovery Area (FRA) : บริหารจัดการสำรองและกู้คืนระดับ Block และช่วยดักจับความเสียหายของบล็อกข้อมูล (Block Corruption)
🏋️ โจทย์ซ้อมเขียนตอบเชิงวิเคราะห์ DBA Lecture ระดับข้อสอบ
ครูเตรียมแนวข้อสอบข้อเขียนเชิงทฤษฎีและการประยุกต์บริหารฐานข้อมูลมาให้ทบทวนครับ:
โจทย์ข้อที่ 1: การวิเคราะห์ประเภท Downtime และแนวทางแก้ไข
คำสั่งโจทย์: บริษัทการเงินแห่งหนึ่งต้องการทำการย้ายที่ตั้งเครื่องเซิร์ฟเวอร์จริง (Server Migration) จากภายในบริษัทขึ้นไปไว้บน Cloud Data Center ในคืนวันอาทิตย์
1) กิจกรรมนี้ถือเป็น Planned หรือ Unplanned Downtime?
2) ในฐานะ DBA คุณจะมีวิธีเตรียมตัวและลดผลกระทบต่อผู้ใช้งานระบบอย่างไร?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
ประเภท Downtime: จัดเป็น Planned Downtime ครับ เนื่องจากเป็นการปิดปรับปรุงระบบตามแผนงานที่กำหนดและคาดหมายไว้ล่วงหน้า
แนวทางการเตรียมตัวเพื่อลดผลกระทบ:
- 1. กำหนดช่วงเวลาบำรุงรักษา (Maintenance Window) ในวันหยุดช่วงที่การใช้งานต่ำสุด เช่น คืนวันอาทิตย์ เวลา 01.00 - 04.00 น.
- 2. แจ้งเตือนลูกค้าและพนักงานผ่านระบบล่วงหน้าอย่างน้อย 3-5 วัน
- 3. ทำการสำรองข้อมูลแบบเต็มระบบ (Full Backup) ตรวจสอบความพร้อมใช้งาน และเก็บประวัติ Rollback Plan ในกรณีที่ย้ายแล้วมีปัญหา จะได้สามารถกู้ฐานข้อมูลเก่าให้รันต่อได้ทันที
- 4. หากธุรกิจต้องการ 0 Downtime อาจต้องประยุกต์ใช้เทคโนโลยี Oracle Data Guard ซิงค์ข้อมูลขึ้น Cloud ล่วงหน้า แล้วใช้ฟังก์ชัน Switchover สลับระบบขึ้นไปแบบไร้ผลกระทบครับ
โจทย์ข้อที่ 2: เปรียบเทียบการเลือกใช้เทคโนโลยี RAID ในองค์กร
คำสั่งโจทย์: ระบบธนาคารพาณิชย์ขนาดใหญ่กำลังจัดซื้อชุดฮาร์ดดิสก์สำหรับเก็บไฟล์ข้อมูลสำคัญอย่าง Datafiles และ Redo Log Files
1) จงเปรียบเทียบข้อดีและข้อจำกัดในการใช้ RAID 5 และ RAID 10 สำหรับงานนี้
2) แนะนำระดับ RAID ที่เหมาะสมที่สุดสำหรับระบบพร้อมอธิบายเหตุผลทางเทคนิค
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
เปรียบเทียบข้อมูลทางเทคนิค:
- RAID 5 (Distributed Parity): ให้พื้นที่ใช้สอยเยอะกว่าและราคาถูกกว่า แต่มีปัญหาเรื่อง Write Penalty (ต้องอ่านข้อมูลเก่า อ่าน parity คำนวณ เขียนข้อมูลใหม่ เขียน parity ใหม่ รวมเป็น 4 I/O) ทำให้การบันทึกคีย์ข้อมูลช้าลง และสามารถทนทานดิสก์พังได้พร้อมกันเพียงแค่ 1 ลูกเท่านั้น
- RAID 10 (Stripe & Mirror): ทำงานได้รวดเร็วมากในการเขียนเพราะไม่ต้องคำนวณ Parity และปลอดภัยสูงมากเนื่องจากทำการโคลนกระจายบล็อกคู่ขนาน ทนดิสก์เสียได้สูงสุดถึง 50% ของระบบ แต่อัตราการสูญเสียเนื้อที่ดิสก์สูงถึง 50%
คำแนะนำ: สำหรับตารางพนักงานหรือไฟล์ธุรกรรมสำคัญระดับการเงิน (Production DB) ควรเลือกใช้ RAID 10 ดีที่สุดครับ เพื่อรับประกันประสิทธิภาพในการรันอ่านเขียนข้อมูลและการสำรองข้อมูลที่เร็วที่สุดในองค์กรครับ
โจทย์ข้อที่ 3: การประเมินและวิเคราะห์ RTO และ RPO
คำสั่งโจทย์: ระบบเว็บจำหน่ายตั๋วคอนเสิร์ตระบุเงื่อนไขการทำงานในเอกสาร SLA ดังนี้: "หากระบบล่ม ข้อมูลคำสั่งซื้อของลูกค้าจะต้องสูญหายได้ไม่เกิน 1 นาทีก่อนหน้านั้น และ DBA ต้องดำเนินการกู้ระบบให้ลูกค้ากลับมาซื้อตั๋วได้ปกติภายใน 15 นาที" จงระบุมาตรวัดและวิธีคำนวณทางเทคนิคของ DBA
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
RPO (Recovery Point Objective): คือ 1 นาที หมายความว่าขอบเขตข้อมูลที่ยอมให้สูญหายได้ยาวสุดหลังจากระบบขัดข้องคือไม่เกิน 1 นาที ทางเทคนิคคือ DBA ต้องจัดทำระบบซิงค์ไฟล์ทรานแซกชันแทบจะแบบ Real-time หรือใช้ Data replication
RTO (Recovery Time Objective): คือ 15 นาที หมายความว่าระยะเวลาจำกัดสูงสุดที่ยอมรับได้ในการกู้ระบบให้ฟื้นคืนกลับมาบริการตามปกติหลังจากเกิดปัญหา ทางเทคนิคคือแอดมินต้องมีเครื่องสำรองที่มีโครงสร้างพร้อมสับเปลี่ยนทำงานอัตโนมัติ (Automated Active-Standby Failover) เพื่อไม่ให้เสียเวลากู้คืนไฟล์แบบแมนนวลที่ใช้เวลาเกิน 15 นาทีครับ
โจทย์ข้อที่ 4: การกู้คืนข้อมูลผิดพลาดด้วย Flashback Technology
คำสั่งโจทย์: พนักงานเผลอรันคำสั่งผิดพลาดโดยไม่ตั้งใจส่งผลให้ข้อมูลในตารางลูกค้าโดนลบทิ้งหมดเกลี้ยง (DROP TABLE) ในวินาทีถัดมา ผู้ใช้แจ้ง DBA ทันที
1) ระหว่างเทคโนโลยี Oracle Data Guard และ Flashback Technology เทคโนโลยีใดช่วยกู้ตารางลูกค้ากลับมาได้รวดเร็วที่สุด? เพราะเหตุใด?
2) หากเลือกวิธีนั้น ข้อมูลในตารางอื่นๆ ที่ไม่ได้ผิดพลาดจะมีผลกระทบอย่างไร?
👁️ ดูแนวคิดและเฉลย
เฉลยและแนววิเคราะห์คำตอบ:
เลือกใช้ Flashback Technology (เฉพาะคำสั่ง Flashback Drop): เพราะระบบ Oracle มีฟีเจอร์ Recycle Bin ที่คอยเก็บันทึกตารางที่พึ่งลบออกไปชั่วคราว ทำให้ DBA สามารถรันเรียกคืนกลับมาได้ทันทีในระดับมิลลิวินาที (เช่น FLASHBACK TABLE customer TO BEFORE DROP;) โดยไม่ต้องปิดการทำงานฐานข้อมูลหรือกู้ไฟล์สำรองขนาดใหญ่ออกมาติดตั้งใหม่
ข้อดีและผลกระทบ: ข้อมูลตารางอื่นๆ จะไม่มีการย้อนเวลากลับตาม จึงไม่ได้รับผลกระทบใดๆ (ไม่สูญเสียข้อมูลธุรกรรมของตารางอื่นที่ทำงานตามปกติในช่วงเวลานั้น) ต่างจากการกู้คืนแบบเต็มระบบ (Restore & Recovery) หรือการสลับไซต์ด้วย Data Guard ที่อาจต้องย้อนสถานะข้อมูลทั้งหมดกลับไป ณ จุดเวลาเดียวกันครับ
📝 จดบันทึกย่อบทเรียน
✓ บันทึกอัตโนมัติแล้ว
Les01: SELECT
Les02: WHERE & Sort
Les03: Functions
Les04: GROUP BY
Les05: JOIN
Les06: Subqueries
Les07: Set Operators
Les08: DML & Trans
Les09: DDL & Tables
Les10: Schema Obj
Les11: Dict Views
Les12: DCL & Access
CTE & Correlated
01 Retrieving Data — SELECT Statement
🎯 ครูบอก: SELECT เป็นพื้นฐานที่สุดของ SQL ต้องจำ Clause Order ให้แม่น: SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY
1. โครงสร้างพื้นฐาน SELECT
SELECT [DISTINCT] column1, column2, ...
FROM table_name
[WHERE condition]
[ORDER BY column [ASC|DESC]];
2. Projection — เลือกคอลัมน์
Syntax ความหมาย ตัวอย่าง
SELECT *เลือกทุกคอลัมน์ SELECT * FROM employees;
SELECT col1, col2เลือกเฉพาะคอลัมน์ที่ระบุ SELECT first_name, salary FROM employees;
col AS aliasตั้งชื่อแทน (Column Alias) SELECT salary * 12 AS annual_salary
col1 || col2ต่อข้อความ (Concatenation) first_name || ' ' || last_name AS full_name
3. Arithmetic Operations กับ NULL
⚠️ กฎเหล็ก: ผลลัพธ์ของการคำนวณใดๆ ที่มี NULL ร่วมด้วย จะได้ผลเป็น NULL เสมอ!
เช่น: salary + NULL = NULL, 5 * NULL = NULL
แก้ด้วย: NVL(commission_pct, 0) — แทน NULL ด้วย 0
4. DESCRIBE
-- ดูโครงสร้างของตาราง (Column names + Data Types)
DESC employees;
-- หรือ
DESCRIBE employees;
5. DISTINCT — กำจัดข้อมูลซ้ำ
-- แสดง department_id ที่ไม่ซ้ำกัน
SELECT DISTINCT department_id FROM employees;
🧠 แบบฝึกหัด — Lab 01: SELECT
ข้อ 1: เขียน SQL แสดงชื่อและเงินเดือนรายปีของพนักงานทุกคน โดยตั้ง Alias ว่า FULL_NAME และ ANNUAL_SALARY
💡 ดูเฉลย
SELECT first_name || ' ' || last_name AS "FULL_NAME",
salary * 12 AS "ANNUAL_SALARY"
FROM employees;
อย่าลืม: ถ้าชื่อ Alias มีช่องว่างหรือตัวพิมพ์เล็กต้องใส่ " " (double quotes)
ข้อ 2: ถ้า employee มีคอลัมน์ commission_pct ที่บางแถวเป็น NULL การคำนวณ
salary + (salary * commission_pct) จะมีปัญหาอะไร และแก้ไขอย่างไร?
💡 ดูเฉลย
ปัญหา: แถวที่ commission_pct เป็น NULL จะได้ผลรวมเป็น NULL ทั้งหมด แม้ว่า salary จะมีค่าอยู่
แก้ด้วย NVL:
SELECT salary + (salary * NVL(commission_pct, 0)) AS total_pay
FROM employees;
NVL(commission_pct, 0) จะแทนค่า NULL ด้วย 0 ทำให้คำนวณได้ถูกต้อง
ข้อ 3: จงอธิบายความแตกต่างระหว่าง
SELECT * กับ
SELECT DISTINCT department_id
💡 ดูเฉลย
SELECT *: คืนทุกแถว ทุกคอลัมน์ รวมถึงแถวที่ข้อมูลซ้ำกัน
SELECT DISTINCT department_id: คืนเฉพาะ department_id ที่ไม่ซ้ำกัน ถ้ามีพนักงาน 50 คนใน 5 แผนก จะได้แค่ 5 แถว
DISTINCT ทำงานกับทุกคอลัมน์ที่เลือก ไม่ใช่แค่คอลัมน์แรก
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 1
โจทย์ 1.1: ดึงข้อมูลรหัสพนักงาน (employee_id), ชื่อและนามสกุลต่อกันตั้งชื่อว่า full_name, เงินเดือนปี (salary * 12) และเงินเดือนปีบวกโบนัสพิเศษ $1,000
💡 ดูเฉลยคำสั่ง SQL
SELECT employee_id,
first_name || ' ' || last_name AS full_name,
salary * 12 AS annual_salary,
(salary * 12) + 1000 AS total_annual_income
FROM employees;
โจทย์ 1.2: แสดงรหัสตำแหน่งงาน (job_id) ทั้งหมดที่มีอยู่ในตาราง employees โดยไม่ให้มีข้อมูลซ้ำ
💡 ดูเฉลยคำสั่ง SQL
SELECT DISTINCT job_id
FROM employees;
02 Restricting & Sorting Data
🎯 ครูบอก: WHERE clause ออกสอบทุกปี! ต้องจำ: BETWEEN (inclusive ทั้งสองด้าน), LIKE (% vs _), IS NULL (ห้ามใช้ = NULL), และ Order of Precedence ของ AND/OR/NOT
1. WHERE Clause — กรองแถว
Operator ความหมาย ตัวอย่าง
=, >, <, >=, <=, <>เปรียบเทียบพื้นฐาน WHERE salary > 5000
BETWEEN x AND yช่วง x ถึง y (รวมปลายทั้งสอง) WHERE salary BETWEEN 3000 AND 8000
IN (list)เท่ากับค่าใดค่าหนึ่งในรายการ WHERE dept_id IN (10, 20, 30)
LIKE patternค้นหาด้วย wildcard WHERE last_name LIKE 'S%'
IS NULL / IS NOT NULLตรวจสอบค่า NULL WHERE commission_pct IS NULL
2. LIKE Wildcards
Wildcard ความหมาย ตัวอย่าง Match กับ
%0 หรือมากกว่า characters LIKE 'J%'J, Jo, John, James
_1 character เท่านั้น LIKE '_a%'James, Paul (ตัวที่ 2 เป็น a)
💡 Escape Character: ถ้าต้องการค้นหาตัว % หรือ _ จริงๆ ใช้ ESCAPE:
WHERE job_id LIKE 'SA\_REP' ESCAPE '' — ค้นหา job_id = 'SA_REP' ตรงๆ
3. Logical Operators: AND / OR / NOT
⚠️ Order of Precedence: NOT > AND > OR
หมายความว่า AND จะทำงานก่อน OR เสมอ! ถ้าไม่แน่ใจ ใส่วงเล็บเสมอ!
-- ถาม: พนักงานใน dept 10 หรือ dept 20 ที่เงินเดือน > 5000
-- ผิด (AND ทำก่อน OR):
WHERE dept_id = 10 OR dept_id = 20 AND salary > 5000
-- ถูก (ใส่วงเล็บ):
WHERE (dept_id = 10 OR dept_id = 20) AND salary > 5000
4. ORDER BY — จัดเรียงผลลัพธ์
-- ASC = น้อยไปมาก (default), DESC = มากไปน้อย
SELECT last_name, salary, hire_date
FROM employees
ORDER BY salary DESC, last_name ASC;
-- เรียงด้วยตำแหน่งคอลัมน์ใน SELECT list
SELECT last_name, salary FROM employees
ORDER BY 2 DESC; -- 2 = salary column
-- NULL values จะอยู่ที่ไหน?
ORDER BY commission_pct NULLS LAST; -- NULL ไปอยู่ท้าย
ORDER BY commission_pct NULLS FIRST; -- NULL อยู่หัว
🧠 แบบฝึกหัด — Lab 02: WHERE & ORDER BY
ข้อ 1: เขียน SQL หาพนักงานที่ชื่อเริ่มด้วย 'A' และเงินเดือนอยู่ระหว่าง 5000-10000 เรียงตามเงินเดือนจากมากไปน้อย
💡 ดูเฉลย
SELECT first_name, last_name, salary
FROM employees
WHERE first_name LIKE 'A%'
AND salary BETWEEN 5000 AND 10000
ORDER BY salary DESC;
ข้อ 2: ผลต่างระหว่าง
WHERE salary = NULL กับ
WHERE salary IS NULL คืออะไร?
💡 ดูเฉลย
WHERE salary = NULL: ไม่มีแถวไหนตรงเลย! เพราะ NULL ไม่สามารถเปรียบเทียบด้วย = ได้ (NULL = NULL ก็ยังเป็น UNKNOWN)
WHERE salary IS NULL: ถูกต้อง! คืนแถวที่ salary เป็น NULL
กฎ: NULL ต้องใช้ IS NULL / IS NOT NULL เสมอ ห้ามใช้ = หรือ != กับ NULL
ข้อ 3: Query นี้จะคืนอะไร?
WHERE dept_id = 10 OR dept_id = 20 AND salary > 5000
💡 ดูเฉลย
เนื่องจาก AND มี precedence สูงกว่า OR ดังนั้น SQL จะตีความเป็น:
WHERE dept_id = 10 OR (dept_id = 20 AND salary > 5000)
ผลลัพธ์: พนักงานใน dept 10 ทุกคน (ไม่ว่าเงินเดือนเท่าไหร่) + พนักงานใน dept 20 ที่เงินเดือน > 5000
ถ้าต้องการ (dept 10 หรือ 20) และเงินเดือน > 5000 ต้องเขียน:
WHERE (dept_id = 10 OR dept_id = 20) AND salary > 5000
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 2
โจทย์ 2.1: ค้นหาพนักงานที่มีเงินเดือนอยู่ในช่วง $5,000 ถึง $10,000 และทำงานในตำแหน่ง 'IT_PROG' หรือ 'SA_REP'
💡 ดูเฉลยคำสั่ง SQL
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary BETWEEN 5000 AND 10000
AND job_id IN ('IT_PROG', 'SA_REP');
โจทย์ 2.2: แสดงนามสกุลพนักงาน, เงินเดือน และค่าคอมมิชชัน โดยเรียงตามค่าคอมมิชชันจากมากไปน้อย หากไม่มีคอมมิชชัน (NULL) ให้ไปแสดงต่อท้ายสุด
💡 ดูเฉลยคำสั่ง SQL
SELECT last_name, salary, commission_pct
FROM employees
ORDER BY commission_pct DESC NULLS LAST, salary DESC;
03 Single-Row Functions (เจาะลึกการใช้ฟังก์ชันระดับแถว)
💡 ทฤษฎีสำคัญที่ออกสอบบ่อย: Single-Row Functions คืออะไร?
Single-Row Functions (ฟังก์ชันระดับแถว): ประมวลผลข้อมูล **ทีละแถว (Row-by-Row)** โดยรับอินพุตเข้าไป 1 ค่า แล้วส่งผลลัพธ์กลับมา 1 ค่าต่อ 1 แถวเสมอ
การนำไปใช้: สามารถใช้ในส่วน `SELECT`, `WHERE`, `ORDER BY` และสามารถเขียนแบบ **ซ้อนฟังก์ชัน (Nesting Functions)** จากข้างในออกข้างนอกได้
ความแตกต่างจาก Multiple-Row (Group) Functions: Group Functions (เช่น SUM, AVG, COUNT) จะรับข้อมูลหลายๆ แถวเข้ามารวมกันแล้วส่งผลลัพธ์กลับมาเพียง **ค่าเดียว**
1. เจาะลึกฟังก์ชันจัดการข้อความ (Character Functions)
แบ่งออกเป็น 2 กลุ่มย่อยหลักตามการทำงาน:
A. Case-Manipulation Functions (แปลงขนาดตัวอักษร)
ฟังก์ชัน
คำอธิบาย
ตัวอย่างการเขียน SQL (ทดสอบผ่าน DUAL)
ผลลัพธ์
LOWER(str)
แปลงทุกอักษรให้เป็น **ตัวพิมพ์เล็ก** ทั้งหมด
SELECT LOWER('SQL Course') FROM DUAL;
'sql course'
UPPER(str)
แปลงทุกอักษรให้เป็น **ตัวพิมพ์ใหญ่** ทั้งหมด
SELECT UPPER('SQL Course') FROM DUAL;
'SQL COURSE'
INITCAP(str)
แปลงอักษร **ตัวแรกของทุกคำให้เป็นพิมพ์ใหญ่** ที่เหลือเป็นพิมพ์เล็ก
SELECT INITCAP('SQL COURSE') FROM DUAL;
'Sql Course'
⚠️ จุดประยุกต์ใช้ในห้องสอบ: การค้นหาแบบ Case-Insensitive
ข้อมูลในตาราง Database มักเก็บแบบสะกดพิมพ์ใหญ่/เล็กไม่เหมือนกัน (เช่น 'Higgins', 'HIGGINS', 'higgins') หากเราใช้
WHERE last_name = 'higgins' จะค้นหาไม่เจอ (no rows selected)
ลอจิกที่ถูกต้อง: ต้องครอบฟังก์ชันเพื่อปรับหน้าตาข้อมูลก่อนเปรียบเทียบ เช่น:
SELECT employee_id, last_name FROM employees WHERE LOWER(last_name) = 'higgins';
B. Character-Manipulation Functions (การหั่น/แต่ง/ดึงข้อมูลข้อความ)
CONCAT(str1, str2): เชื่อมข้อความสองตัวเข้าด้วยกัน (มีค่าเท่ากับการใช้สัญลักษณ์ Pipe || ใน Oracle)
ตัวอย่าง: CONCAT('Hello', 'World') ➜ 'HelloWorld'
SUBSTR(str, position, [length]): หั่นข้อความจากตำแหน่งเริ่มต้นที่กำหนด ดึงยาวออกไปตามความยาวที่ระบุ
💡 กฎเหล็กข้อสอบ:
พิกัดเริ่มต้นเป็น **1-indexed** (เริ่มนับที่ 1)
ถ้า position เป็นบวก จะเริ่มนับจากซ้ายไปขวา เช่น SUBSTR('HelloWorld', 1, 5) ➜ 'Hello'
ถ้า position เป็นลบ จะนับย้อนจากท้ายสุดมาทางซ้าย เช่น SUBSTR('HelloWorld', -5) ➜ 'World' (เริ่มนับจาก W)
หากไม่ระบุ length จะดึงข้อมูลยาวไปจนสุดประโยค
LENGTH(str): นับจำนวนตัวอักษรของข้อความ (รวมช่องว่าง)
ตัวอย่าง: LENGTH('HelloWorld') ➜ 10
INSTR(str, substring, [position, occurrence]): ค้นหาตำแหน่งเริ่มต้นของคำย่อยในประโยค (หากไม่เจอจะส่งกลับเลข 0)
ตัวอย่าง: INSTR('HelloWorld', 'W') ➜ 6 (ตัว W อยู่ในตำแหน่งลำดับที่ 6)
LPAD(str, total_length, pad_char) / RPAD: เติมอักษรเสริมด้านซ้ายหรือขวาให้ได้ความยาวรวมที่ต้องการ
ตัวอย่าง: LPAD(salary, 10, '*') ➜ '*****24000' (ช่วยในการแสดงสลิปเงินเดือนหรือบัตรเครดิต)
REPLACE(str, search_str, replace_str): ค้นหาคำเป้าหมายแล้วแทนที่ด้วยคำใหม่ทั้งหมด
ตัวอย่าง: REPLACE('JACK and JILL', 'J', 'BL') ➜ 'BLACK and BLILL'
TRIM([both|leading|trailing] char FROM str): ตัดตัวอักษรส่วนเกิน (หรือช่องว่าง) ออกจากหัวและท้ายข้อความ
ตัวอย่าง: TRIM('H' FROM 'HelloWorldH') ➜ 'elloWorld'
2. เจาะลึกฟังก์ชันตัวเลข (Number Functions)
ฟังก์ชันคณิตศาสตร์ที่จัดการทศนิยมและหาเศษ:
ฟังก์ชัน
คำอธิบาย
ตัวอย่าง SQL (ผ่านตาราง DUAL)
ผลลัพธ์
ROUND(num, dec)
ปัดเศษทศนิยม ขึ้น/ลง ตามหลักคณิตศาสตร์ทั่วไป
ROUND(45.926, 2)
ROUND(45.926, 0)
ROUND(45.926, -1)
45.93
46
50 (ปัดหลักหน่วยขยับขึ้นหลักสิบ)
TRUNC(num, dec)
ตัดทศนิยมทิ้ง ณ ตำแหน่งนั้นทันทีโดยไม่มีการปัดขึ้น
TRUNC(45.926, 2)
TRUNC(45.926, 0)
TRUNC(45.926, -1)
45.92
45
40 (ตัดหลักหน่วยทิ้งเป็นศูนย์)
MOD(num, div)
หา เศษเหลือจากการหาร (Modulo)
SELECT MOD(1600, 300) FROM DUAL;
100 (หารได้ 5 เหลือเศษ 100)
📁 เกร็ดความรู้ห้องสอบ: ตาราง DUAL คืออะไร?
DUAL คือตารางจำลองระบบพิเศษ (Dummy Table) ที่เป็นเจ้าของโดยผู้ดูแลระบบ SYS มีคุณลักษณะเด่นคือ **มี 1 แถว และ 1 คอลัมน์ (ชื่อคอลัมน์ DUMMY ค่าเป็น 'X')**
💡 เหตุผลที่ต้องใช้: ไวยากรณ์ SQL ของ Oracle บังคับว่าคำสั่ง SELECT ทุกครั้งจะต้องระบุ FROM [ชื่อตาราง] เสมอ ดังนั้นเวลาที่เราต้องการคำนวณเลขหรือทดสอบฟังก์ชันเดี่ยวๆ ที่ไม่ได้เกี่ยวข้องกับข้อมูลในตารางใดๆ เราจะส่งไปประมวลผลผ่านตาราง DUAL นี้
3. เจาะลึกฟังก์ชันวันที่และการคำนวณ (Date Functions)
ระบบ Oracle เก็บวันที่ในรูปแบบตัวเลขภายใน (Internal Numeric) ครอบคลุมศตวรรษ, ปี, เดือน, วัน, ชั่วโมง, นาที, วินาที โดยค่าแสดงผลเริ่มต้นคือ DD-MON-RR
A. การคำนวณทางคณิตศาสตร์กับวันที่ (Date Arithmetic)
Date - Date: คืนค่าเป็น **จำนวนวัน** ที่ต่างกันระหว่างสองวันที่ (เช่น SYSDATE - hire_date)
Date + Number: บวกจำนวนวันเข้าไปในวันที่เพื่อหาเป้าหมายปลายทาง
Date + Number/24: บวกจำนวนชั่วโมงเข้าไปในวันที่นั้นๆ
B. ฟังก์ชันจัดการวันที่ที่ต้องเข้าใจก่อนสอบ
SYSDATE: ส่งคืนวันที่และเวลาปัจจุบันของเซิร์ฟเวอร์ระบบ
MONTHS_BETWEEN(date1, date2): หาจำนวนเดือนที่ห่างกันระหว่างสองช่วงเวลา (เอาค่ามากไว้ซ้ายเสมอเพื่อไม่ให้ติดลบ)
ตัวอย่าง: MONTHS_BETWEEN('01-SEP-95', '11-JAN-94') ➜ 19.677419
ADD_MONTHS(date, n): บวกเพิ่มหรือลดจำนวนเดือนเชิงปฏิทินเข้าไปในวันที่
ตัวอย่าง: ADD_MONTHS('11-JAN-94', 6) ➜ '11-JUL-94'
NEXT_DAY(date, 'DAY_OF_WEEK'): หาวันถัดไปที่เป็นชื่อวันที่ระบุ (เช่น หาพิกัดวันศุกร์ถัดไปหลังจากวันนี้)
ตัวอย่าง: NEXT_DAY('24-MAY-04', 'FRIDAY') ➜ '28-MAY-04'
LAST_DAY(date): ส่งคืนวันที่วันสุดท้ายของเดือนนั้นๆ (เช่น เช็คว่าเดือนกุมภาพันธ์ปีนั้นมี 28 หรือ 29 วัน)
ตัวอย่าง: LAST_DAY('01-FEB-04') ➜ '29-FEB-04' (ปีอธิกสุรทิน)
ROUND / TRUNC กับวันที่:
ROUND(SYSDATE, 'MONTH') ➜ หากเลยวันที่ 15 ของเดือนไปแล้ว จะปัดขึ้นเป็นวันที่ 1 ของเดือนถัดไป หากไม่ถึงปัดลงวันที่ 1 เดือนเดิม
TRUNC(SYSDATE, 'MONTH') ➜ ตัดเศษเวลาและวันทิ้ง ปัดกลับไปเป็นวันที่ 1 ของเดือนปัจจุบันทันที
4. เจาะลึกฟังก์ชันแปลงประเภทข้อมูล (Conversion Functions)
เมื่อต้องการเชื่อมโยงหรือเปรียบเทียบข้อมูลต่างชนิดกันอย่างถูกต้อง ป้องกันความผิดพลาดของระบบ:
TO_NUMBER() ───► NUMBER ◄─── TO_CHAR()
TO_DATE() ───► DATE ◄─── TO_CHAR()
5. เจาะลึกฟังก์ชันจัดการค่าว่าง (General & Null Handling Functions)
ค่าว่าง (NULL) เมื่อนำไปคำนวณทางคณิตศาสตร์มักส่งผลให้ผลลัพธ์กลายเป็น NULL เสมอ จึงต้องมีกลุ่มฟังก์ชันจัดการสิ่งนี้:
NVL(expr1, expr2): หาก expr1 เป็นค่าว่าง (NULL) จะส่งกลับ expr2 ออกมาแทน หากไม่ใช่ส่งค่าเดิมออกไป
⚠️ กฎห้ามลืม: ข้อมูลของ expr1 และ expr2 **ต้องเป็นชนิดข้อมูลชนิดเดียวกัน**
ตัวอย่าง: NVL(commission_pct, 0) ➜ หากพนักงานไม่มีค่าคอมฯ จะใส่เลข 0 แทนเพื่อใช้คูณสูตรรายได้
NVL2(expr1, expr2, expr3): ตรวจสอบว่า expr1 เป็น NULL หรือไม่?
ถ้า ไม่ใช่ NULL ➜ ส่งคืน expr2
ถ้า เป็น NULL ➜ ส่งคืน expr3
ตัวอย่าง: NVL2(commission_pct, 'SAL+COMM', 'SAL') ➜ เพื่อจัดกลุ่มประเภทเงินได้พนักงาน
NULLIF(expr1, expr2): เปรียบเทียบค่าสองค่า
ถ้า เท่ากัน ➜ จะส่งคืนค่า NULL
ถ้า ไม่เท่ากัน ➜ จะส่งคืนค่าแรกคือ expr1
ตัวอย่าง: NULLIF(LENGTH(first_name), LENGTH(last_name)) ➜ จะคืนค่า NULL หากพนักงานมีชื่อและนามสกุลยาวเท่ากันพอดี
COALESCE(expr1, expr2, ..., exprn): ฟังก์ชันขั้นสูงที่ตรวจสอบหาค่าที่ไม่ใช่ NULL ค่าแรกในลิสต์พารามิเตอร์ที่เรียงไว้
ข้อดีเหนือ NVL: รับอาร์กิวเมนต์ได้หลายตัวและจะตรวจสอบเรียงลำดับไปเรื่อยๆ จนกว่าจะเจอตัวที่มีค่า
6. เจาะลึกฟังก์ชันเงื่อนไข (Conditional Expressions)
ช่วยให้เราสามารถเขียนลอจิกเงื่อนไขประเภท IF-THEN-ELSE ได้โดยตรงในคำสั่งคิวรี่:
A. CASE Expression (รูปแบบมาตรฐานสากล ANSI SQL - แนะนำใช้ทั่วไป)
SELECT last_name, job_id, salary,
CASE job_id WHEN 'IT_PROG' THEN 1.10*salary
WHEN 'ST_CLERK' THEN 1.15*salary
ELSE salary END "REVISED_SALARY"
FROM employees;
B. DECODE Function (ฟังก์ชันพิเศษเฉพาะของ Oracle เท่านั้น)
SELECT last_name, job_id, salary,
DECODE(job_id, 'IT_PROG', 1.10*salary,
'ST_CLERK', 1.15*salary,
salary) "REVISED_SALARY"
FROM employees;
🏋️ โจทย์ซ้อมเขียนมือระดับข้อสอบ & เฉลยคำสั่งทีละบรรทัด
ครูเตรียมแบบฝึกหัดท้าทายระดับข้อสอบจริง 5 ข้อ ให้นักเรียนได้ฝึกหัดเขียนคิดวิเคราะห์คำสั่งด้วยตนเองครับ:
โจทย์ข้อที่ 1: การจัดการแต่งข้อความ
คำสั่งโจทย์: แสดงรายชื่อพนักงานทุกคนโดยจัดให้อยู่ในรูปแบบ [อักษรแรกของชื่อจริงพิมพ์ใหญ่]. [นามสกุลตัวพิมพ์ใหญ่ทั้งหมด] ตั้งชื่อคอลัมน์ว่า FULL_NAME และคอลัมน์ความยาวของนามสกุลพนักงาน ตั้งชื่อว่า LAST_LEN
👁️ ดูแนวคิดและเฉลย SQL
วิเคราะห์ลอจิก:
ดึงอักษรตัวแรกของชื่อจริงมาแปลงพิมพ์ใหญ่ด้วย INITCAP(SUBSTR(first_name, 1, 1))
ทำนามสกุลพิมพ์ใหญ่ทั้งหมดด้วย UPPER(last_name)
เชื่อมประโยคเข้าด้วยกันด้วยตัวเชื่อม || หรือฟังก์ชัน CONCAT
นับความยาวนามสกุลด้วย LENGTH(last_name)
SELECT INITCAP(SUBSTR(first_name, 1, 1)) || '. ' || UPPER(last_name) AS FULL_NAME,
LENGTH(last_name) AS LAST_LEN
FROM employees;
โจทย์ข้อที่ 2: การคำนวณอายุงานจากวันที่
คำสั่งโจทย์: คำนวณหาจำนวน **ปี** ที่พนักงานทำงานมาจนถึงปัจจุบัน (นับจากวันจ้าง hire_date) ปรับรูปแบบให้แสดงเป็นคำพูดต่อท้ายเช่น '15 years' และคอลัมน์วันทำงานสุดท้ายในเดือนที่จ้างของพนักงานแต่ละคน
👁️ ดูแนวคิดและเฉลย SQL
วิเคราะห์ลอจิก:
หาความต่างของเดือนทั้งหมดด้วย MONTHS_BETWEEN(SYSDATE, hire_date)
หารด้วย 12 เพื่อหาจำนวนปี และปัดเศษทศนิยมทิ้งทั้งหมดเพื่อความแม่นยำด้วย TRUNC(..., 0)
เชื่อมคำว่า ' years' ต่อท้ายข้อความ
หาวันสุดท้ายของเดือนที่จ้างด้วย LAST_DAY(hire_date)
SELECT last_name,
TRUNC(MONTHS_BETWEEN(SYSDATE, hire_date) / 12, 0) || ' years' AS EXPERIENCE,
LAST_DAY(hire_date) AS FIRST_MONTH_END
FROM employees;
โจทย์ข้อที่ 3: จัดการค่า NULL และความสอดประสานชนิดข้อมูล
คำสั่งโจทย์: ดึงนามสกุลและอัตราส่วนค่าคอมมิชชันของพนักงานทุกคนมาแสดง ถ้าคอมมิชชันเป็น NULL ให้แสดงคำว่า 'No Comm' แต่ถ้าไม่ใช่ NULL ให้แปลงคอมมิชชันเป็นร้อยละพร้อมเครื่องหมาย % เช่น '30%' ตั้งชื่อคอลัมน์ว่า COMM_STATUS
👁️ ดูแนวคิดและเฉลย SQL
วิเคราะห์ลอจิก:
เนื่องจากเงื่อนไขต้องการแสดงผลทั้งข้อความ ('No Comm') และตัวเลขแปลงรูปแบบ ('30%') ซึ่งเป็น String ทั้งคู่
หากเราใช้ NVL ตรงๆ เช่น NVL(commission_pct, 'No Comm') จะฟ้องข้อผิดพลาดเรื่องชนิดข้อมูลขัดแย้ง เพราะช่องคอมฯ เป็นตัวเลขแต่ค่าทดแทนเป็นสตริง
เราจึงใช้ฟังก์ชัน NVL2 ตรวจสอบเงื่อนไข และใช้ TO_CHAR แปลงคอมมิชชันเป็นเปอร์เซ็นต์ไว้ก่อน
SELECT last_name,
NVL2(commission_pct, TO_CHAR(commission_pct * 100) || '%', 'No Comm') AS COMM_STATUS
FROM employees;
โจทย์ข้อที่ 4: การซ้อนฟังก์ชันและการสืบค้นเฉพาะทาง
คำสั่งโจทย์: จงระบุตัวอักษรลำดับแรกที่เป็นตัวอักษร 'a' (พิมพ์เล็ก) ในนามสกุลพนักงาน โดยมีเงื่อนไขการเลือกคือ: นามสกุลของพนักงานคนนั้นต้องมีความยาวมากกว่า 5 อักษร และอักษรตัวสุดท้ายของนามสกุลต้องเป็นตัว 's' พิมพ์เล็กเท่านั้น
👁️ ดูแนวคิดและเฉลย SQL
วิเคราะห์ลอจิก:
หาตำแหน่งของอักษร 'a' ด้วย INSTR(last_name, 'a')
เช็คความยาวนามสกุลด้วย LENGTH(last_name) > 5 ใน WHERE clause
เช็คอักษรตัวสุดท้ายโดยใช้ SUBSTR เริ่มจากด้านขวาย้อนมา 1 ตัวคือ SUBSTR(last_name, -1) = 's'
SELECT last_name,
INSTR(last_name, 'a') AS A_POSITION
FROM employees
WHERE LENGTH(last_name) > 5
AND SUBSTR(last_name, -1) = 's';
โจทย์ข้อที่ 5: การประยุกต์ใช้ DECODE แบ่งสเกล
คำสั่งโจทย์: แสดงระดับเงินเดือนพนักงาน โดยแบ่งกลุ่มด้วย DECODE: พนักงานที่ได้เงินเดือนต่ำกว่า 5,000 ให้ระบุเป็น 'Tier 1', พนักงานที่ได้เงินเดือนตั้งแต่ 5,000 ถึง 9,999 ให้ระบุเป็น 'Tier 2', นอกเหนือจากนั้นระบุเป็น 'Tier 3'
👁️ ดูแนวคิดและเฉลย SQL
วิเคราะห์ลอจิก:
ฟังก์ชัน DECODE จะทำการจับคู่ค่าตรงตัว (Equi-join) ไม่สามารถเช็คค่าเปรียบเทียบช่วง < หรือ > ได้โดยตรง
เราจึงต้องประยุกต์ใช้การคำนวณคณิตศาสตร์: นำเงินเดือนหารด้วย 5,000 แล้วตัดเศษทศนิยมทิ้งด้วย TRUNC(salary / 5000)
- หากเงินเดือนอยู่ระหว่าง 0 - 4,999 จะหารออกมาได้ 0.xx ➜ TRUNC จะปัดเศษเป็น 0
- หากเงินเดือนอยู่ระหว่าง 5,000 - 9,999 จะหารออกมาได้ 1.xx ➜ TRUNC จะปัดเศษเป็น 1
- นอกเหนือจากนั้นจะได้ค่าตั้งแต่ 2 ขึ้นไป
นำค่าผลลัพธ์นี้ไปให้ DECODE ทำงานจับคู่เงื่อนไข
SELECT last_name, salary,
DECODE(TRUNC(salary / 5000), 0, 'Tier 1',
1, 'Tier 2',
'Tier 3') AS SALARY_TIER
FROM employees;
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 3
โจทย์ 3.1: แสดงชื่อพนักงานเป็นตัวพิมพ์ใหญ่ (UPPER), ความยาวของนามสกุล (LENGTH), และ 3 อักษรแรกของอีเมล (SUBSTR) สำหรับพนักงานที่นามสกุลลงท้ายด้วยตัว 'n'
💡 ดูเฉลยคำสั่ง SQL
SELECT UPPER(first_name) AS first_upper,
last_name,
LENGTH(last_name) AS name_len,
SUBSTR(email, 1, 3) AS email_prefix
FROM employees
WHERE LOWER(last_name) LIKE '%n';
โจทย์ 3.2: คำนวณรายได้รวมจริง salary + (salary * NVL(commission_pct, 0)) และใช้ CASE แปลงรหัสแผนก 10 ➔ 'Admin', 20 ➔ 'Marketing', 30 ➔ 'Purchasing', อื่นๆ ➔ 'Other'
💡 ดูเฉลยคำสั่ง SQL
SELECT last_name, salary,
salary + (salary * NVL(commission_pct, 0)) AS total_income,
CASE department_id
WHEN 10 THEN 'Administration'
WHEN 20 THEN 'Marketing'
WHEN 30 THEN 'Purchasing'
ELSE 'Other Departments'
END AS dept_category
FROM employees;
04 Group Functions & Aggregation
🎯 ครูบอก: ต้องแม่น 3 เรื่อง: 1) COUNT(*) vs COUNT(col), 2) GROUP BY ต้องครอบ non-aggregate columns, 3) HAVING กรองกลุ่ม WHERE กรองแถว
1. Group Functions หลัก
Function คำอธิบาย NULL handling
COUNT(*)นับจำนวนแถวทั้งหมด นับรวม NULL ด้วย
COUNT(col)นับแถวที่คอลัมน์นั้นไม่ใช่ NULL ข้ามแถว NULL
SUM(col)ผลรวม ข้าม NULL
AVG(col)ค่าเฉลี่ย = SUM/COUNT(col) ข้าม NULL (ระวัง!)
MIN(col)ค่าต่ำสุด ข้าม NULL
MAX(col)ค่าสูงสุด ข้าม NULL
⚠️ AVG กับ NULL:
พนักงาน 4 คน เงินเดือน: 3000, 5000, NULL, 7000
AVG(salary) = (3000+5000+7000)/3 = 5000 (ข้าม NULL, หารด้วย 3)
ถ้าต้องการรวม NULL เป็น 0: AVG(NVL(salary, 0)) = 15000/4 = 3750
2. GROUP BY
-- ข้อบังคับ: ทุก column ใน SELECT ที่ไม่ใช่ aggregate function
-- ต้องอยู่ใน GROUP BY ด้วย!
-- ถูก:
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id;
-- ผิด! (first_name ไม่ได้อยู่ใน GROUP BY)
SELECT department_id, first_name, AVG(salary) -- ERROR!
FROM employees
GROUP BY department_id;
3. HAVING — กรองกลุ่ม
-- WHERE กรองแถวก่อน Group, HAVING กรองกลุ่มหลัง Group
SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_sal
FROM employees
WHERE job_id != 'SA_MAN' -- กรองแถวก่อน (ไม่รวม Manager)
GROUP BY department_id
HAVING AVG(salary) > 8000 -- กรองกลุ่มที่เงินเดือนเฉลี่ย > 8000
ORDER BY avg_sal DESC;
🧠 แบบฝึกหัด — Lab 04: Group Functions
ข้อ 1: เขียน SQL หาจำนวนพนักงาน เงินเดือนสูงสุด-ต่ำสุด และค่าเฉลี่ย แยกตามแผนก เฉพาะแผนกที่มีพนักงานมากกว่า 5 คน เรียงตามค่าเฉลี่ยมากไปน้อย
💡 ดูเฉลย
SELECT department_id,
COUNT(*) AS emp_count,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5
ORDER BY avg_salary DESC;
ข้อ 2: อธิบายความแตกต่างระหว่าง WHERE และ HAVING พร้อมยกตัวอย่างที่ใช้ทั้งสองพร้อมกัน
💡 ดูเฉลย
WHERE HAVING
ทำงานเมื่อ ก่อน GROUP BY หลัง GROUP BY
กรอง แต่ละแถว แต่ละกลุ่ม
ใช้กับ Aggregate ❌ ไม่ได้ ✅ ได้
SELECT department_id, AVG(salary)
FROM employees
WHERE job_id != 'AD_PRES' -- กรอง: ไม่รวม President
GROUP BY department_id
HAVING AVG(salary) > 6000; -- กรอง: เฉพาะแผนกที่เฉลี่ย > 6000
ข้อ 3: ทำไม
COUNT(*) ถึงให้ผลต่างกับ
COUNT(commission_pct)?
💡 ดูเฉลย
COUNT(*) นับทุกแถวในตาราง รวมแถวที่มี NULL ด้วย
COUNT(commission_pct) นับเฉพาะแถวที่ commission_pct ไม่ใช่ NULL
ตัวอย่าง: ถ้ามีพนักงาน 107 คน แต่มีเพียง 35 คนที่ได้รับ commission
• COUNT(*) = 107
• COUNT(commission_pct) = 35
ใช้ประโยชน์: นับจำนวนพนักงานที่ได้รับ commission: SELECT COUNT(commission_pct) FROM employees;
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 4
โจทย์ 4.1: แสดงรหัสแผนก, จำนวนพนักงาน, เงินเดือนเฉลี่ย (ปัดทศนิยม 2 ตำแหน่ง), และเงินเดือนสูงสุดของแต่ละแผนก โดยกรองเฉพาะแผนกที่มีเงินเดือนเฉลี่ยมากกว่า $7,000
💡 ดูเฉลยคำสั่ง SQL
SELECT department_id,
COUNT(*) AS emp_count,
ROUND(AVG(salary), 2) AS avg_salary,
MAX(salary) AS max_salary
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id
HAVING AVG(salary) > 7000
ORDER BY avg_salary DESC;
05 Joining Multiple Tables
🎯 ครูบอก: JOIN ออกสอบแน่นอน! ต้องแยกให้ออกระหว่าง INNER JOIN, LEFT/RIGHT OUTER JOIN และ SELF JOIN ฝึกเขียนทั้งแบบ SQL:1999 (JOIN ON) และแบบ Oracle (WHERE)
1. ประเภทของ JOIN
JOIN Type คืนข้อมูล ตัวอย่าง
INNER JOIN / JOIN เฉพาะแถวที่มีคู่ตรงกันในทั้งสองตาราง พนักงานที่สังกัดแผนก
LEFT OUTER JOIN ทุกแถวจากตารางซ้าย + แถวที่ตรงกันจากขวา (NULL ถ้าไม่มี) พนักงานทุกคน รวมที่ไม่มีแผนก
RIGHT OUTER JOIN ทุกแถวจากตารางขวา + แถวที่ตรงกันจากซ้าย ทุกแผนก รวมแผนกที่ไม่มีพนักงาน
FULL OUTER JOIN ทุกแถวจากทั้งสองตาราง พนักงานทุกคน + ทุกแผนก
SELF JOIN JOIN ตารางกับตัวเอง ใช้ Alias หา Manager ของพนักงานแต่ละคน
CROSS JOIN Cartesian Product (ทุก combination) m แถว × n แถว = m×n แถว
2. ตัวอย่าง JOIN Syntax
-- NATURAL JOIN (join อัตโนมัติตามชื่อคอลัมน์ที่เหมือนกัน)
SELECT employee_id, last_name, department_name
FROM employees NATURAL JOIN departments;
-- JOIN...USING (ระบุคอลัมน์)
SELECT employee_id, last_name, department_name
FROM employees JOIN departments USING (department_id);
-- JOIN...ON (ยืดหยุ่นที่สุด ใช้ชื่อต่างกันได้)
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id;
-- LEFT OUTER JOIN
SELECT e.last_name, d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id = d.department_id;
-- SELF JOIN (หา Manager ของพนักงาน)
SELECT e.last_name AS employee, m.last_name AS manager
FROM employees e JOIN employees m
ON e.manager_id = m.employee_id;
🧠 แบบฝึกหัด — Lab 05: Joins
ข้อ 1: เขียน SQL แสดงชื่อพนักงาน ชื่อแผนก และเมือง (city) ที่พนักงานทำงานอยู่
💡 ดูเฉลย
SELECT e.last_name, d.department_name, l.city
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;
ต้อง JOIN 3 ตาราง: employees → departments → locations เชื่อมทีละขั้น
ข้อ 2: อธิบายความแตกต่างระหว่าง INNER JOIN และ LEFT OUTER JOIN พร้อมยกสถานการณ์ที่ควรใช้แต่ละแบบ
💡 ดูเฉลย
INNER JOIN: คืนเฉพาะแถวที่มีคู่ตรงกันในทั้งสองตาราง
ใช้เมื่อ: ต้องการข้อมูลที่สมบูรณ์เท่านั้น เช่น พนักงานที่สังกัดแผนกจริงๆ
LEFT OUTER JOIN: คืนทุกแถวจากตารางซ้าย ถ้าไม่มีคู่จะได้ NULL
ใช้เมื่อ: ต้องการข้อมูลครบทุกแถวจากตารางหลัก เช่น
"แสดงพนักงานทุกคน แม้ว่าบางคนยังไม่ได้สังกัดแผนก"
SELECT e.last_name, d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id = d.department_id;
แถวพนักงานที่ไม่มีแผนกจะแสดง department_name เป็น NULL
ข้อ 3: เขียน SELF JOIN เพื่อแสดงชื่อพนักงาน และชื่อผู้จัดการ (manager) ของพนักงานคนนั้น
💡 ดูเฉลย
SELECT e.last_name AS "Employee",
m.last_name AS "Manager"
FROM employees e
LEFT OUTER JOIN employees m ON e.manager_id = m.employee_id
ORDER BY m.last_name NULLS LAST;
ใช้ LEFT OUTER JOIN เพื่อรวม CEO ที่ไม่มี manager (manager_id = NULL)
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 5
โจทย์ 5.1: แสดงนามสกุลพนักงาน (last_name), ชื่อตำแหน่งงาน (job_title), ชื่อแผนก (department_name), และเมือง (city) โดยทำการ JOIN 4 ตาราง (employees, jobs, departments, locations)
💡 ดูเฉลยคำสั่ง SQL
SELECT e.last_name, j.job_title, d.department_name, l.city
FROM employees e
JOIN jobs j ON e.job_id = j.job_id
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;
โจทย์ 5.2: แสดงชื่อพนักงานคู่กับชื่อผู้จัดการโดยใช้ SELF JOIN และ LEFT OUTER JOIN เพื่อให้แสดงพนักงานทุกคนแม้ไม่มีผู้จัดการ (เช่น CEO)
💡 ดูเฉลยคำสั่ง SQL
SELECT e.last_name AS employee_name,
NVL(m.last_name, 'No Manager') AS manager_name
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.employee_id;
06 Using Subqueries to Solve Queries
🎯 ครูบอก: Subquery ออกสอบบ่อยมาก! จำให้แม่น: Single-row ใช้ =, >, <; Multi-row ใช้ IN, ANY, ALL; และระวัง NULL ใน NOT IN!
1. ประเภทของ Subquery
ประเภท คืนข้อมูล Operators
Single-Row Subquery 1 แถว, 1 คอลัมน์ =, >, <, >=, <=, <>
Multi-Row Subquery หลายแถว, 1 คอลัมน์ IN, NOT IN, ANY, ALL
Multi-Column Subquery หลายแถว, หลายคอลัมน์ IN (col1, col2)
2. Single-Row Subquery
-- หาพนักงานที่ได้รับเงินเดือนเท่ากับ Abel
SELECT last_name, salary
FROM employees
WHERE salary = (SELECT salary
FROM employees
WHERE last_name = 'Abel');
-- หาพนักงานที่เงินเดือนสูงกว่าค่าเฉลี่ย
SELECT last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY salary;
3. Multi-Row Subquery: IN, ANY, ALL
-- IN: เท่ากับค่าใดค่าหนึ่งในรายการ
SELECT last_name FROM employees
WHERE department_id IN
(SELECT department_id FROM departments WHERE location_id = 1700);
-- ANY: เปรียบเทียบกับค่าใดค่าหนึ่ง (< ANY = น้อยกว่าค่าสูงสุด)
SELECT last_name, salary FROM employees
WHERE salary < ANY (SELECT salary FROM employees WHERE job_id = 'IT_PROG');
-- ALL: เปรียบเทียบกับทุกค่า (< ALL = น้อยกว่าทุกค่า = น้อยกว่าค่าต่ำสุด)
SELECT last_name, salary FROM employees
WHERE salary < ALL (SELECT salary FROM employees WHERE job_id = 'IT_PROG');
🚨 กับดัก NULL ใน NOT IN!
ถ้า Subquery คืนผลลัพธ์ที่มี NULL อยู่ด้วย NOT IN จะไม่คืนแถวใดเลย!
เพราะ x NOT IN (1, 2, NULL) = x <> 1 AND x <> 2 AND x <> NULL = UNKNOWN
แก้: ใส่ WHERE col IS NOT NULL ใน Subquery
🧠 แบบฝึกหัด — Lab 06: Subqueries
ข้อ 1: เขียน SQL หาพนักงานที่ได้รับเงินเดือนสูงที่สุดในบริษัท
💡 ดูเฉลย
SELECT last_name, salary
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);
ใช้ Single-Row Subquery เพราะ MAX() คืน 1 ค่าเสมอ
ข้อ 2: จงอธิบายความแตกต่างระหว่าง
< ANY และ
< ALL พร้อมยกตัวอย่าง
💡 ดูเฉลย
สมมติ Subquery คืน: (3000, 5000, 8000)
< ANY (3000, 5000, 8000):
หมายถึง "น้อยกว่าค่าใดค่าหนึ่ง" = น้อยกว่า 8000 (ค่าสูงสุด)
ผลลัพธ์: salary < 8000
< ALL (3000, 5000, 8000):
หมายถึง "น้อยกว่าทุกค่า" = น้อยกว่า 3000 (ค่าต่ำสุด)
ผลลัพธ์: salary < 3000
สรุป: x < ANY(list) = x < MAX(list) | x < ALL(list) = x < MIN(list)
ข้อ 3: ทำไม NOT IN จึงเป็นอันตรายเมื่อ Subquery อาจคืน NULL? และจะแก้ไขอย่างไร?
💡 ดูเฉลย
ปัญหา: x NOT IN (1, 2, NULL) แปลงเป็น:
x <> 1 AND x <> 2 AND x <> NULL
เนื่องจาก
x <> NULL = UNKNOWN → ทั้ง AND chain เป็น UNKNOWN
ดังนั้น WHERE จะไม่คืนแถวใดเลย!
วิธีแก้:
-- เพิ่ม IS NOT NULL ใน subquery
SELECT employee_id FROM employees
WHERE manager_id NOT IN
(SELECT manager_id FROM employees WHERE manager_id IS NOT NULL);
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 6
โจทย์ 6.1: ค้นหาชื่อพนักงานและเงินเดือน ของคนที่ได้เงินเดือนมากกว่าเงินเดือนเฉลี่ยของบริษัท (Single-Row Subquery)
💡 ดูเฉลยคำสั่ง SQL
SELECT first_name, last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
โจทย์ 6.2: ค้นหาชื่อพนักงานที่ทำงานอยู่ในแผนกเดียวกับพนักงานที่มีนามสกุล 'Taylor' (Multi-Row Subquery)
💡 ดูเฉลยคำสั่ง SQL
SELECT last_name, department_id, salary
FROM employees
WHERE department_id IN (SELECT department_id
FROM employees
WHERE last_name = 'Taylor');
07 Using the Set Operators
🎯 ครูบอก: Set Operators ออกสอบเรื่อง "เลือก Operator ที่เหมาะสม" และ "กฎการใช้งาน" ต้องจำ: UNION vs UNION ALL, INTERSECT, MINUS และกฎ 3 ข้อ!
1. Set Operators คืออะไร?
ใช้รวม ตัด หรือหาส่วนร่วมของผลลัพธ์จาก SELECT หลายชุด เสมือนทฤษฎีเซต (Set Theory)
2. กฎการใช้ Set Operators (สำคัญมาก!)
📌 กฎ 3 ข้อที่ต้องจำ:
1. จำนวนคอลัมน์ต้องเท่ากัน ในทุก SELECT
2. ชนิดข้อมูลต้องเข้ากันได้ (compatible) ในแต่ละตำแหน่ง
3. ชื่อคอลัมน์ในผลลัพธ์ใช้ตาม SELECT แรก
Operator ความหมาย ซ้ำ? เรียง?
UNION รวมผลลัพธ์ทั้งสอง ❌ ไม่ซ้ำ ✅ เรียงอัตโนมัติ
UNION ALL รวมผลลัพธ์ทั้งสอง ✅ รวมซ้ำด้วย ❌ ไม่เรียง
INTERSECT เฉพาะที่มีในทั้งสอง ❌ ไม่ซ้ำ ✅ เรียงอัตโนมัติ
MINUS มีใน SELECT1 แต่ไม่มีใน SELECT2 ❌ ไม่ซ้ำ ✅ เรียงอัตโนมัติ
3. ตัวอย่าง
-- UNION: พนักงานในแผนก 10 หรือ Job = SA_REP (ไม่ซ้ำ)
SELECT employee_id, last_name FROM employees WHERE department_id = 10
UNION
SELECT employee_id, last_name FROM employees WHERE job_id = 'SA_REP';
-- INTERSECT: พนักงานที่อยู่ใน dept 10 และ เป็น SA_REP
SELECT employee_id FROM employees WHERE department_id = 10
INTERSECT
SELECT employee_id FROM employees WHERE job_id = 'SA_REP';
-- MINUS: พนักงาน dept 10 ที่ไม่ใช่ SA_REP
SELECT employee_id FROM employees WHERE department_id = 10
MINUS
SELECT employee_id FROM employees WHERE job_id = 'SA_REP';
🧠 แบบฝึกหัด — Lab 07: Set Operators
ข้อ 1: จงบอกความแตกต่างระหว่าง UNION กับ UNION ALL พร้อมระบุว่าควรใช้แบบไหนในสถานการณ์ใด
💡 ดูเฉลย
UNION UNION ALL
ข้อมูลซ้ำ ลบออก (distinct) เก็บไว้ทั้งหมด
ความเร็ว ช้ากว่า (ต้อง sort เพื่อ deduplicate) เร็วกว่า
ใช้เมื่อ ต้องการข้อมูลไม่ซ้ำ เช่น รายชื่อลูกค้าทั้งหมด ต้องการทุกแถว เช่น รวม log จากหลาย period
ข้อ 2: กฎ 3 ข้อที่ต้องปฏิบัติเมื่อใช้ Set Operators คืออะไร?
💡 ดูเฉลย
1.
จำนวนคอลัมน์ต้องเท่ากัน — ทุก SELECT statement ต้อง SELECT จำนวน column เท่ากัน
2.
ชนิดข้อมูลต้องเข้ากันได้ในตำแหน่งเดียวกัน — column แรกของทุก SELECT ต้องเป็น type ที่ compatible (เช่น NUMBER กับ NUMBER, VARCHAR กับ VARCHAR)
3.
ชื่อคอลัมน์ผลลัพธ์มาจาก SELECT แรก — ถ้าต้องการ Alias ให้ใส่ใน SELECT แรกเท่านั้น
ตัวอย่างที่ผิด:
SELECT employee_id, last_name FROM employees -- 2 columns
UNION
SELECT department_id FROM departments; -- 1 column (ERROR!)
ข้อ 3: ถ้าต้องการหาพนักงานที่เคยทำงานในแผนก 20 หรือ 30 แต่ตอนนี้ไม่ได้อยู่แผนกใดแผนกหนึ่งนั้นแล้ว ควรใช้ Set Operator ใด?
💡 ดูเฉลย
ใช้
MINUS
(พนักงานที่เคยอยู่ dept 20 หรือ 30) MINUS (พนักงานที่ปัจจุบันอยู่ dept 20 หรือ 30)
SELECT employee_id FROM job_history
WHERE department_id IN (20, 30)
MINUS
SELECT employee_id FROM employees
WHERE department_id IN (20, 30);
job_history เก็บประวัติการทำงาน employees เก็บข้อมูลปัจจุบัน
🏛️ โจทย์ท้าทายจาก HR Schema (Hr_main) — บทที่ 7
โจทย์ 7.1: แสดงรหัสพนักงาน (employee_id) และรหัสตำแหน่ง (job_id) ของพนักงานที่เคยย้ายตำแหน่งในตาราง job_history และปัจจุบันยังกลับมาทำงานในตำแหน่งเดิมนั้นอยู่ (ใช้ INTERSECT)
💡 ดูเฉลยคำสั่ง SQL
SELECT employee_id, job_id FROM employees
INTERSECT
SELECT employee_id, job_id FROM job_history;
โจทย์ 7.2: แสดงรหัสตำแหน่งงาน (job_id) ทั้งหมดในตาราง jobs แต่ยังไม่มีพนักงานคนใดทำตำแหน่งนั้นเลยใน employees (ใช้ MINUS)
💡 ดูเฉลยคำสั่ง SQL
SELECT job_id FROM jobs
MINUS
SELECT job_id FROM employees;
08 Manipulating Data — DML & Transaction Control
🎯 ครูบอก: บทนี้เน้น DML (INSERT, UPDATE, DELETE, MERGE) และ Transaction Control (COMMIT, ROLLBACK, SAVEPOINT) เรื่องที่ออกสอบบ่อยมากคือ "กับดักลืม WHERE ใน UPDATE/DELETE" และ "ความแตกต่างระหว่าง DELETE vs TRUNCATE" ครับ!
1. คำสั่งการจัดการข้อมูล (DML Statements)
DML (Data Manipulation Language) ใช้สำหรับเพิ่ม แก้ไข หรือลบข้อมูลในตาราง โดยผลของการทำ DML จะยังไม่เปลี่ยนข้อมูลในดิสก์ถาวรจนกว่าจะทำ COMMIT
1.1 INSERT Statement — เพิ่มข้อมูลใหม่
-- 1. เพิ่มแถวข้อมูลตรงๆ (ระบุค่าครบทุกคอลัมน์)
INSERT INTO departments (department_id, department_name, manager_id, location_id)
VALUES (280, 'Data Analytics', 103, 1700);
-- 2. เพิ่มข้อมูลเฉพาะคอลัมน์ที่กำหนด (คอลัมน์ที่ไม่ระบุจะเป็น NULL)
INSERT INTO departments (department_id, department_name)
VALUES (290, 'Cyber Security');
-- 3. เพิ่มข้อมูลจากการคัดลอกอีกตารางผ่าน SELECT (Subquery Insert)
INSERT INTO sales_reps (id, name, salary, commission_pct)
SELECT employee_id, last_name, salary, commission_pct
FROM employees
WHERE job_id LIKE 'SA_%';
1.2 UPDATE Statement — แก้ไขข้อมูล
-- แก้ไขค่าในคอลัมน์ที่ต้องการ
UPDATE employees
SET salary = salary * 1.10,
commission_pct = 0.15
WHERE employee_id = 104;
-- UPDATE ด้วย Subquery (ดึงค่าจ้างและตำแหน่งของพนักงาน 103 มาใส่ให้ 105)
UPDATE employees
SET (job_id, salary) = (SELECT job_id, salary
FROM employees
WHERE employee_id = 103)
WHERE employee_id = 105;
🚨 กับดักอันตรายในข้อสอบ:
ถ้าเขียน UPDATE employees SET salary = 9000; โดยไม่มี WHERE clause — เงินเดือนของพนักงานทุกคนในตารางจะถูกเปลี่ยนเป็น 9000 ทั้งหมด! ต้องระวัง WHERE เสมอ!
1.3 DELETE vs. TRUNCATE
คุณลักษณะ
DELETE Statement
TRUNCATE Statement
ประเภทคำสั่ง
DML (Data Manipulation Language)
DDL (Data Definition Language)
การกรองเงื่อนไข
ใช้ WHERE ลบเฉพาะบางแถวได้
ลบข้อมูลออกหมดทั้งตาราง (ห้ามมี WHERE)
การย้อนคืน (Rollback)
ย้อนคืนได้ด้วยคำสั่ง ROLLBACK
ย้อนคืนไม่ได้! ทำ Auto-Commit ทันที
ความเร็วและการใช้ทรัพยากร
ช้ากว่า (สร้าง Redo Log ละเอียดทีละแถว)
เร็วกว่ามาก (ปล่อย Data Extents คืนระบบ)
1.4 MERGE Statement (Upsert)
ใช้ปรับปรุงข้อมูลแบบเงื่อนไข: ถ้ามีข้อมูลอยู่แล้วให้ทำ UPDATE แต่ถ้ายังไม่มีให้ทำ INSERT ในคำสั่งเดียว
MERGE INTO copy_emp c
USING employees e
ON (c.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET c.first_name = e.first_name,
c.salary = e.salary
WHEN NOT MATCHED THEN
INSERT (c.employee_id, c.first_name, c.last_name, c.salary)
VALUES (e.employee_id, e.first_name, e.last_name, e.salary);
2. การควบคุมธุรกรรม (Transaction Control & Read Consistency)
Transaction (ธุรกรรม): กลุ่มของคำสั่ง DML ที่ถือเป็นงานก้อนเดียวกัน มีจุดเริ่มเมื่อเริ่มทำ DML แรก และสิ้นสุดเมื่อสั่ง COMMIT หรือ ROLLBACK
-- เริ่มทำ DML
INSERT INTO departments VALUES (300, 'R&D', NULL, 1700);
SAVEPOINT sp_after_insert;
UPDATE employees SET salary = salary + 500 WHERE department_id = 300;
-- ย้อนคืนเฉพาะงานหลัง SAVEPOINT
ROLLBACK TO sp_after_insert;
-- บันทึกเปลี่ยนแปลงทั้งหมดลงดิสก์ถาวร
COMMIT;
💡 หลักการ Read Consistency (ความสอดคล้องในการอ่าน):
ผู้ใช้อื่นในระบบจะยังไม่เห็นการเปลี่ยนแปลง DML ของเรา จนกว่าเราจะสั่ง COMMIT! ในระหว่างนั้นข้อมูลดั้งเดิมจะถูกอ่านมาจาก Undo Tablespace
🧠 แบบฝึกหัด — Lab 08: DML & Transactions
ข้อ 1: จงอธิบายความแตกต่างระหว่าง DELETE และ TRUNCATE ใน 3 ประเด็นหลัก (คำสั่ง, การใช้ Rollback, ความเร็ว)
💡 ดูเฉลย
1. ประเภทคำสั่ง: DELETE เป็น DML | TRUNCATE เป็น DDL
2. การย้อนคืน (Rollback): DELETE สามารถ ROLLBACK คืนข้อมูลได้ | TRUNCATE ย้อนคืนไม่ได้ (Auto-Commit)
3. ความเร็ว: DELETE ลบทีละแถวและบันทึก Redo Log จึงช้ากว่า | TRUNCATE ปล่อย Data Block คืนระบบทันที จึงเร็วกว่ามาก
ข้อ 2: เขียน SQL MERGE เพื่อปรับปรุงตาราง
emp_target โดยเทียบกับ
emp_source ด้วย
employee_id ถ้าเจอให้ UPDATE เงินเดือน ถ้าไม่เจอให้ INSERT ข้อมูลใหม่
💡 ดูเฉลย
MERGE INTO emp_target t
USING emp_source s
ON (t.employee_id = s.employee_id)
WHEN MATCHED THEN
UPDATE SET t.salary = s.salary
WHEN NOT MATCHED THEN
INSERT (t.employee_id, t.first_name, t.salary)
VALUES (s.employee_id, s.first_name, s.salary);
ข้อ 3: สมมติทำ
INSERT ➔
SAVEPOINT A ➔
UPDATE ➔
SAVEPOINT B ➔
DELETE ➔
ROLLBACK TO A จะเกิดอะไรขึ้นกับข้อมูล?
💡 ดูเฉลย
คำสั่ง UPDATE และ DELETE ที่เกิดขึ้นหลัง SAVEPOINT A จะถูกยกเลิก (Rollback) ทั้งหมด!
เหลือเฉพาะผลของคำสั่ง INSERT แรกสุดที่ทำก่อน SAVEPOINT A (ซึ่งยังคงอยู่สถานะ Uncommitted รอคำสั่ง COMMIT หรือ ROLLBACK ต่อไป)
09 DDL Statements — Creating & Managing Tables
🎯 ครูบอก: บทนี้เน้น DDL (CREATE, ALTER, DROP, TRUNCATE) และ Constraints 5 ชนิด เรื่องสำคัญที่ต้องจำคือ DDL ทำ Auto-Commit ทันที และกู้คืนตารางที่ลบด้วย FLASHBACK TABLE ... TO BEFORE DROP ครับ!
1. คำสั่งกำหนดโครงสร้าง (DDL Statements)
DDL (Data Definition Language) ใช้สร้าง เปลี่ยนแปลง หรือลบอ็อบเจกต์ในฐานข้อมูล ทุกคำสั่ง DDL จะสั่ง COMMIT อัตโนมัติ (ไม่สามารถ ROLLBACK ได้)
2. ชนิดข้อมูลพื้นฐานใน Oracle (Data Types)
Data Type
คำอธิบายและขนาด
ตัวอย่างการใช้งาน
VARCHAR2(size)
ตัวอักษรความยาวแปรผัน (Variable-length string) สูงสุด 4000 bytes
VARCHAR2(50) เก็บชื่อ, อีเมล
CHAR(size)
ตัวอักษรความยาวคงที่ (Fixed-length string) ถ้าใส่ไม่ครบจะเติมช่องว่าง
CHAR(13) เลขบัตรประชาชน, CHAR(1) เพศ
NUMBER(p, s)
ตัวเลข precision p หลัก, scale s ทศนิยม
NUMBER(8,2) เงินเดือน (สูงสุด 999999.99)
DATE
วันที่และเวลา (Century, Year, Month, Day, Hour, Minute, Second)
hire_date DATE
3. ข้อกำหนดความสมบูรณ์ข้อมูล (Constraints 5 ชนิด)
CREATE TABLE project_emp (
emp_id NUMBER(6) CONSTRAINT prj_emp_id_pk PRIMARY KEY,
email VARCHAR2(100) CONSTRAINT prj_email_uk UNIQUE,
first_name VARCHAR2(50) NOT NULL,
salary NUMBER(8,2) CONSTRAINT prj_sal_ck CHECK (salary > 0),
dept_id NUMBER(4),
CONSTRAINT prj_dept_fk FOREIGN KEY (dept_id)
REFERENCES departments(department_id) ON DELETE CASCADE
);
Constraint
เงื่อนไขและพฤติกรรม
NOT NULL
ห้ามคอลัมน์นี้มีค่าเป็น NULL (ต้องระบุระดับ Column Level เท่านั้น)
UNIQUE
ห้ามค่าซ้ำกันในตาราง แต่ยินยอมให้เป็น NULL ได้หลายแถว
PRIMARY KEY
กุญแจหลัก = UNIQUE + NOT NULL (ใน 1 ตารางมีได้เพียง 1 PK เท่านั้น)
FOREIGN KEY
กุญแจนอกอ้างอิงไปยัง PK ตารางอื่น (ON DELETE CASCADE = ลบลูกตามแม่)
CHECK
ตรวจสอบเงื่อนไขความถูกต้องของข้อมูล เช่น CHECK (salary > 0)
4. การแก้ไขตารางด้วย ALTER TABLE
-- 1. เพิ่มคอลัมน์ใหม่
ALTER TABLE project_emp ADD (phone_number VARCHAR2(20));
-- 2. แก้ไขขนาดคอลัมน์ หรือเปลี่ยนเป็น NOT NULL
ALTER TABLE project_emp MODIFY (phone_number VARCHAR2(30) NOT NULL);
-- 3. ลบคอลัมน์
ALTER TABLE project_emp DROP COLUMN phone_number;
-- 4. กู้คืนตารางที่เพิ่งลบไป (Flashback Table)
DROP TABLE project_emp;
FLASHBACK TABLE project_emp TO BEFORE DROP;
🧠 แบบฝึกหัด — Lab 09: DDL & Constraints
ข้อ 1: ความแตกต่างระหว่าง PRIMARY KEY และ UNIQUE Constraint คืออะไร?
💡 ดูเฉลย
• PRIMARY KEY: ห้ามซ้ำและห้ามเป็น NULL ( UNIQUE + NOT NULL ) มีได้เพียง 1 กุญแจต่อ 1 ตาราง
• UNIQUE: ห้ามซ้ำ แต่ยอมรับค่า NULL ได้ และตารางหนึ่งสามารถมี UNIQUE Constraints ได้หลายคอลัมน์
ข้อ 2: เขียน DDL สร้างตาราง
course มี
course_id (NUMBER PRIMARY KEY),
title (VARCHAR2(100) NOT NULL),
credits (NUMBER CHECK > 0)
💡 ดูเฉลย
CREATE TABLE course (
course_id NUMBER(5) PRIMARY KEY,
title VARCHAR2(100) NOT NULL,
credits NUMBER(2) CHECK (credits > 0)
);
ข้อ 3: ถ้าเผลอลบตารางด้วยคำสั่ง
DROP TABLE my_data; จะกู้คืนตารางกลับมาได้อย่างไร? และกรณีใดที่ไม่สามารถกู้คืนได้?
💡 ดูเฉลย
• วิธี กู้คืน: ใช้คำสั่ง FLASHBACK TABLE my_data TO BEFORE DROP; (ดึงกลับจาก Recycle Bin)
• กรณีที่ไม่สามารถกู้ได้: ลบตารางด้วยคำสั่ง DROP TABLE my_data PURGE; (คำสั่ง PURGE จะลบออกจาก Recycle Bin ถาวรทันที)
10 Creating Other Schema Objects — Views, Sequences, Indexes & Synonyms
🎯 ครูบอก: บทนี้ออกสอบเรื่อง Schema Objects ครบทุกตัว: (1) Simple vs Complex View และ WITH CHECK OPTION (2) Sequence (NEXTVAL/CURRVAL) (3) เมื่อไหร่ควรสร้าง Index และ (4) Synonym ครับ!
1. View (วิว - ตารางจำลอง)
View คือ ตารางเสมือนที่สร้างขึ้นจากคำสั่ง SELECT เพื่อจำกัดสิทธิ์เข้าถึงคอลัมน์ หรือเพื่อซ่อนความซับซ้อนของการ JOIN ตาราง
คุณลักษณะ
Simple View (วิวอย่างง่าย)
Complex View (วิวซับซ้อน)
จำนวนตารางอ้างอิง
อ้างอิงตารางเดียว (Single Table)
อ้างอิงหลายตาราง (Multiple Tables / JOIN)
Group Functions / GROUP BY
ไม่มี Group Functions
มี Group Functions (SUM, AVG) หรือ GROUP BY
การทำ DML ผ่าน View
ทำ DML (INSERT/UPDATE/DELETE) ได้
ทำ DML ไม่ได้โดยตรง
-- สร้าง Simple View พร้อม WITH CHECK OPTION
CREATE OR REPLACE VIEW emp_dept20_vu AS
SELECT employee_id, last_name, salary, department_id
FROM employees
WHERE department_id = 20
WITH CHECK OPTION CONSTRAINT emp_dept20_ck;
-- WITH CHECK OPTION ป้องกันการ UPDATE/INSERT ข้อมูลที่มี department_id != 20 ผ่าน View นี้!
-- วิวที่ห้ามทำ DML เด็ดขาด (Read Only)
CREATE OR REPLACE VIEW emp_summary_vu AS
SELECT department_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY department_id
WITH READ ONLY;
2. Sequence (ตัวเจนลำดับตัวเลขอัตโนมัติ)
-- สร้าง Sequence
CREATE SEQUENCE dept_seq
START WITH 300
INCREMENT BY 10
MAXVALUE 9999
NOCACHE
NOCYCLE;
-- เรียกใช้งาน Sequence
-- NEXTVAL: เจนเลขถัดไป | CURRVAL: อ่านเลขปัจจุบันใน Session
INSERT INTO departments (department_id, department_name)
VALUES (dept_seq.NEXTVAL, 'Digital Marketing');
3. Index (ดัชนีเร่งความเร็วในการค้นหา)
ควรสร้าง Index เมื่อ
ไม่ควรสร้าง Index เมื่อ
• คอลัมน์ที่ถูกค้นใน WHERE หรือ JOIN บ่อยๆ • ตารางมีขนาดใหญ่มาก และคิวรี่ดึงข้อมูลไม่เกิน 2-4% ของแถวทั้งหมด • คอลัมน์มีค่าหลากหลายมาก (High Cardinality)
• ตารางขนาดเล็ก • คอลัมน์ไม่ได้ถูกใช้ในเงื่อนไขการค้นหา • ตารางมีการทำ DML (INSERT/UPDATE) บ่อยมาก (การมี Index มากไปทำให้ DML ช้าลง)
4. Synonym (ชื่อนามแฝง)
-- สร้าง Synonym ส่วนตัว เพื่อไม่ต้องพิมพ์ hr.employees ยอดนิยม
CREATE SYNONYM emp FOR hr.employees;
SELECT * FROM emp; -- ใช้งานแทนตารางเต็มได้ทันที
🧠 แบบฝึกหัด — Lab 10: View, Sequence & Index
ข้อ 1: คำสั่ง
WITH CHECK OPTION ในการสร้าง View มีประโยชน์อย่างไร?
💡 ดูเฉลย
ประโยชน์คือ ป้องกันการ INSERT หรือ UPDATE ข้อมูลผ่าน View ที่ทำให้แถวนั้นไม่ตรงกับเงื่อนไข WHERE ใน View อีกต่อไป
ตัวอย่าง: View กรองเฉพาะ `dept_id = 20` หากมี `WITH CHECK OPTION` จะไม่ยอมให้ UPDATE แก้ไข `dept_id` เป็น 30 ผ่าน View นี้ได้
ข้อ 2: `NEXTVAL` และ `CURRVAL` ของ Sequence ต่างกันอย่างไร? และต้องใช้อันไหนก่อน?
💡 ดูเฉลย
• `NEXTVAL`: ใช้สร้างและคืนค่าลำดับตัวเลขถัดไป
• `CURRVAL`: ใช้เรียกอ่านค่าลำดับล่าสุดที่เพิ่งสร้างใน Session ปัจจุบัน
• ลำดับการใช้: ต้องเรียกใช้ `NEXTVAL` อย่างน้อย 1 ครั้งใน Session ก่อนเสมอ จึงจะสามารถอ้างอิง `CURRVAL` ได้
ข้อ 3: เหตุใดตารางที่มีการ `INSERT` และ `UPDATE` ข้อมูลบ่อยมาก จึงไม่ควรสร้าง Index หลายอัน?
💡 ดูเฉลย
เพราะทุกครั้งที่มีการ INSERT, UPDATE หรือ DELETE แถวข้อมูลในตารางหลัก **Oracle จะต้องเสียเวลาอัปเดตโครงสร้าง B-Tree ของ Index ทุกอันที่เกี่ยวข้องไปพร้อมกันด้วย** ทำให้ประสิทธิภาพของคำสั่ง DML ช้าลงอย่างมาก
11 Managing Objects with Data Dictionary Views
🎯 ครูบอก: Data Dictionary คือพจนานุกรมคลังข้อมูลระบบที่ Oracle สร้างขึ้นโดยอัตโนมัติ ออกสอบเรื่องการจำแนกคำนำหน้า USER_, ALL_, DBA_ และ V$ ครับ!
1. Data Dictionary คืออะไร?
Data Dictionary เป็นชุดตารางอ้างอิง Read-Only ที่จัดเก็บ Metadata (ข้อมูลอธิบายโครงสร้างระบบ) ทั้งหมดของฐานข้อมูล Oracle เช่น รายชื่อตาราง, สิทธิ์การใช้งาน, ข้อกำหนด Constraints และสถิติต่างๆ
2. ระดับการเข้าถึง Data Dictionary Views
Prefix
ขอบเขตข้อมูลที่แสดง
ตัวอย่าง View
USER_
อ็อบเจกต์ที่ผู้ใช้คนนั้นเป็นเจ้าของ (Owner) เท่านั้น
USER_TABLES, USER_VIEWS
ALL_
อ็อบเจกต์ที่ผู้ใช้เป็นเจ้าของ + อ็อบเจกต์ที่ได้รับสิทธิ์เข้าถึงจากผู้อื่น
ALL_TABLES, ALL_CONSTRAINTS
DBA_
อ็อบเจกต์ทั้งหมดในทั้งฐานข้อมูล (สำหรับผู้ดูแลระบบ DBA)
DBA_USERS, DBA_DATA_FILES
V$ / GV$
Dynamic Performance Views แสดงสถิติการทำงาน Real-time ใน Memory
V$SESSION, V$DATABASE, V$INSTANCE
3. ตัวอย่างคำสั่งคิวรี่ Data Dictionary ที่ออกสอบบ่อย
-- 1. ดูรายชื่อตารางทั้งหมดที่เราเป็นเจ้าของ
SELECT table_name, num_rows FROM user_tables;
-- 2. ดูชื่อและเงื่อนไข Constraints ของตาราง EMPLOYEES
SELECT constraint_name, constraint_type, search_condition
FROM user_constraints
WHERE table_name = 'EMPLOYEES';
-- 3. ดูคอร์สคำสั่ง SQL เบื้องหลังของ View
SELECT view_name, text
FROM user_views
WHERE view_name = 'EMP_DEPT20_VU';
🧠 แบบฝึกหัด — Lab 11: Data Dictionary Views
ข้อ 1: ความแตกต่างระหว่าง `USER_TABLES`, `ALL_TABLES` และ `DBA_TABLES` คืออะไร?
💡 ดูเฉลย
• USER_TABLES: แสดงเฉพาะตารางที่เราสร้างเอง (Owner)
• ALL_TABLES: แสดงตารางที่เราสร้างเอง + ตารางคนอื่นที่เราได้รับสิทธิ์ GRANT เข้าถึง
• DBA_TABLES: แสดงตารางของทุกคนทั้งระบบฐานข้อมูล (ผู้ใช้ต้องมีสิทธิ์ DBA จึงจะเรียกดูได้)
ข้อ 2: คำสั่ง SQL ใดใช้สำหรับตรวจสอบข้อกำหนด Constraints ทั้งหมดของตาราง
DEPARTMENTS?
💡 ดูเฉลย
SELECT constraint_name, constraint_type, search_condition
FROM user_constraints
WHERE table_name = 'DEPARTMENTS';
*(ข้อควรจำ: ชื่อตารางใน Data Dictionary ต้องเป็นตัวพิมพ์ใหญ่ 'DEPARTMENTS' เสมอ)*
12 Controlling User Access — DCL & Privileges
🎯 ครูบอก: บทนี้เน้นความปลอดภัยและการจัดการสิทธิ์ (DCL): System Privileges vs. Object Privileges , คำสั่ง GRANT / REVOKE, WITH GRANT OPTION และประโยชน์ของ Role ครับ!
1. สิทธิ์การใช้งานใน Oracle (Privileges)
DCL (Data Control Language) คือ คำสั่งบริหารจัดการความปลอดภัยของฐานข้อมูล แบ่งเป็น 2 ประเภท:
ประเภทสิทธิ์
คำอธิบายและขอบเขต
ตัวอย่างคำสั่งสิทธิ์
System Privileges
สิทธิ์บริหารจัดการระบบในระดับกว้าง (System-wide action)
CREATE SESSION (สิทธิ์ล็อกอิน), CREATE TABLE, CREATE USER
Object Privileges
สิทธิ์ในการทำกระบวนการกับอ็อบเจกต์เฉพาะเจาะจงในตาราง/วิว
SELECT, INSERT, UPDATE, DELETE, EXECUTE
2. การให้สิทธิ์ (GRANT) และการริบสิทธิ์คืน (REVOKE)
-- 1. มอบสิทธิ์ระดับระบบ (System Privilege) ให้ผู้ใช้ new_user
GRANT CREATE SESSION, CREATE TABLE TO new_user;
-- 2. มอบสิทธิ์ระดับอ็อบเจกต์ (Object Privilege) พร้อม WITH GRANT OPTION
GRANT SELECT, INSERT ON hr.employees TO alice WITH GRANT OPTION;
-- (WITH GRANT OPTION = ยินยอมให้ alice นำสิทธิ์ SELECT/INSERT นี้ไปมอบต่อให้ผู้อื่นได้)
-- 3. ริบสิทธิ์คืน (REVOKE)
REVOKE INSERT ON hr.employees FROM alice;
3. บทบาทและกลุ่มสิทธิ์ (Roles)
Role คือ กลุ่มของสิทธิ์ที่ถูกตั้งชื่อรวมกัน เพื่อให้ง่ายต่อการมอบสิทธิ์แก่ผู้ใช้จำนวนมากพร้อมกัน
-- สร้าง Role และเพิ่มสิทธิ์เข้าไปใน Role
CREATE ROLE app_developer;
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW TO app_developer;
-- มอบ Role ให้ผู้ใช้หลายคนในคำสั่งเดียว
GRANT app_developer TO user1, user2, user3;
🧠 แบบฝึกหัด — Lab 12: Privileges & Roles
ข้อ 1: System Privileges และ Object Privileges ต่างกันอย่างไร? ยกตัวอย่างประเภทละ 2 คำสั่ง
💡 ดูเฉลย
• System Privileges: สิทธิ์การทำงานระดับระบบ เช่น `CREATE SESSION` (สิทธิ์ล็อกอิน), `CREATE TABLE`
• Object Privileges: สิทธิ์จัดการข้อมูลในอ็อบเจกต์เฉพาะตาราง เช่น `SELECT ON hr.employees`, `UPDATE ON hr.departments`
ข้อ 2: คำสั่ง `WITH GRANT OPTION` มีหน้าที่อะไร? และมีข้อควรระวังอย่างไร?
💡 ดูเฉลย
• หน้าที่: อนุญาตให้ผู้ที่ได้รับสิทธิ์ สามารถนำสิทธิ์นั้นไปมอบ (GRANT) ต่อให้กับผู้ใช้งานคนอื่นต่อไปได้
• ข้อควรระวัง: อาจเกิดปัญหาความปลอดภัยหากผู้ใช้นำสิทธิ์ไปแจกจ่ายโดยไม่ได้รับอนุญาตจาก DBA
13 CTE & Correlated Subqueries (Advanced SQL)
🎯 ครูบอก: บทนี้เน้น SQL ขั้นสูงที่ออกสอบอัตนัยบ่อยที่สุด: (1) Common Table Expressions (CTE ด้วย WITH) (2) Recursive CTE สร้างผังองค์กร และ (3) Correlated Subquery ร่วมกับ EXISTS / NOT EXISTS ครับ!
1. Common Table Expressions (CTE - คำสั่ง WITH)
CTE คือ การสร้างตารางชั่วคราวที่มีชื่ออ้างอิงได้ในคิวรี่ ด้วยคำสั่ง WITH ช่วยแยกตรรกะซับซ้อนให้เป็นบล็อก อ่านง่ายขึ้น และสามารถอ้างอิงซ้ำได้หลายครั้งในคิวรี่เดียว
-- 1. ตัวอย่าง CTE พื้นฐาน (หาพนักงานที่เงินเดือนสูงกว่าค่าเฉลี่ยแผนกตนเอง)
WITH dept_avg AS (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
)
SELECT e.first_name, e.last_name, e.salary, d.avg_salary
FROM employees e
JOIN dept_avg d ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;
-- 2. CTE ผสาน Window Function (หา Top 3 เงินเดือนสูงสุดของแต่ละแผนก)
WITH ranked_employees AS (
SELECT first_name, last_name, department_id, salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees
)
SELECT department_id, first_name, last_name, salary
FROM ranked_employees
WHERE rnk <= 3;
2. Recursive CTE (คิวรี่วนซ้ำสร้างผังสายบังคับบัญชา)
ใช้สำหรับดึงข้อมูลโครงสร้างลำดับชั้น (Hierarchy Structure) เช่น ผังองค์กร โดยประกอบด้วย 2 ส่วนเชื่อมด้วย UNION ALL:
1. Anchor Member: จุดเริ่มต้นบนสุดของลำดับชั้น (เช่น WHERE manager_id IS NULL)
2. Recursive Member: คิวรี่ที่ JOIN ตารางเดิมเข้ากับ CTE เพื่อไล่หาลูกน้องในระดับถัดไป
WITH org_chart (employee_id, first_name, last_name, manager_id, emp_level) AS (
-- Anchor: CEO / President
SELECT employee_id, first_name, last_name, manager_id, 1
FROM employees
WHERE manager_id IS NULL
UNION ALL
-- Recursive: ลูกน้องระดับถัดไป
SELECT e.employee_id, e.first_name, e.last_name, e.manager_id, oc.emp_level + 1
FROM employees e
JOIN org_chart oc ON e.manager_id = oc.employee_id
)
SELECT LPAD(' ', (emp_level-1)*2) || first_name || ' ' || last_name AS org_tree,
emp_level
FROM org_chart
ORDER BY emp_level, last_name;
3. Correlated Subquery & EXISTS / NOT EXISTS
Correlated Subquery: ซับคิวรี่ที่มีการอ้างอิงคอลัมน์จากคิวรี่ภายนอก (ประมวลผลซ้ำทีละแถวของ Outer Query)
-- หาพนักงานที่เป็นผู้จัดการ (มีลูกน้องอย่างน้อย 1 คน) ด้วย EXISTS
SELECT e.employee_id, e.last_name
FROM employees e
WHERE EXISTS (SELECT 1
FROM employees m
WHERE m.manager_id = e.employee_id);
-- หาแผนกที่ไม่มีพนักงานอยู่เลยด้วย NOT EXISTS (ปลอดภัยจาก NULL!)
SELECT d.department_id, d.department_name
FROM departments d
WHERE NOT EXISTS (SELECT 1
FROM employees e
WHERE e.department_id = d.department_id);
4. ตารางเปรียบเทียบ CTE vs. Subquery vs. View
คุณลักษณะ
CTE (คำสั่ง WITH)
Subquery
View
อายุการใช้งาน
ชั่วคราวเฉพาะในคำสั่งนั้น
ชั่วคราวเฉพาะในคำสั่งนั้น
ถาวรใน Schema จนกว่าจะ DROP
อ้างอิงซ้ำในคำสั่งเดียว
ทำได้หลายครั้งในคำสั่งเดียว
ทำไม่ได้ (ต้องเขียนโค้ดซ้ำ)
ทำได้หลายครั้ง
การรองรับ Recursion
รองรับ (UNION ALL)
ไม่รองรับ
ไม่รองรับโดยตรง
🧠 แบบฝึกหัด — Lab 13: CTE & Advanced Subqueries
ข้อ 1: เหตุใดการใช้ `NOT EXISTS` จึงปลอดภัยและแนะนำมากกว่า `NOT IN` เมื่อต้องคิวรี่หาข้อมูลที่ไม่เกี่ยวข้องกัน?
💡 ดูเฉลย
เพราะถ้าผลลัพธ์จาก Subquery มีค่า NULL ติดมาด้วย คำสั่ง `NOT IN` จะคืนผลลัพธ์เป็นว่าง (0 แถว) ทันทีเนื่องจากกฎ UNKNOWN ในตรรกศาสตร์ แต่ `NOT EXISTS` ตรวจสอบการมีอยู่ของแถว (Boolean test) จึงปลอดภัยจากปัญหา NULL 100%
ข้อ 2: เขียน CTE เพื่อสรุปยอดรวมเงินเดือนแยกตามแผนก แล้วหาแผนกที่มียอดรวมเงินเดือนมากกว่า 50,000
💡 ดูเฉลย
WITH dept_sal AS (
SELECT department_id, SUM(salary) AS total_sal
FROM employees
GROUP BY department_id
)
SELECT department_id, total_sal
FROM dept_sal
WHERE total_sal > 50000;