MS-SQL

เจาะลึก MS-SQL Trigger (AFTER & INSTEAD OF) พร้อมวิธีจัดการ Error ด้วย TRY...CATCH

9 นาที 15 views บันทึกเป็น PDF
เจาะลึก MS-SQL Trigger (AFTER & INSTEAD OF) พร้อมวิธีจัดการ Error ด้วย TRY...CATCH

เรียนรู้การใช้ Trigger ใน MS-SQL เพื่อจัดการข้อมูลอัตโนมัติ พร้อมเทคนิคการเขียน Error Handling ให้ระบบเสถียร ไม่พังง่าย เหมาะสำหรับมือใหม่หัดเขียนฐานข้อมูล

Trigger คืออะไรและทำไมต้องรู้จัก

เวลาเราทำงานกับฐานข้อมูล บางครั้งเราต้องการให้ระบบทำงานบางอย่างโดยอัตโนมัติเมื่อเกิดเหตุการณ์บางอย่างขึ้น เช่น เมื่อมีการลบข้อมูลพนักงานออก เราอยากให้ระบบย้ายข้อมูลนั้นไปเก็บในตารางสำรองทันทีโดยที่เราไม่ต้องสั่งเอง Trigger (ตัวกระตุ้นการทำงานอัตโนมัติ) คือเครื่องมือที่ช่วยจัดการเรื่องนี้ได้ดีที่สุดใน MS-SQL

ลองนึกภาพว่าคุณมีพนักงานคอยเฝ้าหน้าประตูร้าน ถ้าลูกค้าเดินเข้าประตูมาพนักงานคนนี้จะกล่าวต้อนรับทันทีโดยไม่ต้องรอให้คุณสั่ง นี่คือหลักการทำงานของ Trigger ในฐานข้อมูล มันจะคอยเฝ้าดูคำสั่ง Query (คำสั่งถามหรือจัดการข้อมูล) อย่างเช่นการเพิ่ม การแก้ไข หรือการลบข้อมูลในตารางที่คุณกำหนดไว้

การใช้ Trigger ช่วยให้ข้อมูลในฐานข้อมูลของเรามีความถูกต้องและเป็นระบบอยู่เสมอ โดยเฉพาะเมื่อเรามีตารางที่ต้องสัมพันธ์กันหลายจุด การเขียนโค้ดไว้ที่ตัวฐานข้อมูลโดยตรงจะช่วยป้องกันความผิดพลาดจากการลืมสั่งงานผ่านแอปพลิเคชันได้เป็นอย่างดี ถือเป็นทักษะสำคัญที่โปรแกรมเมอร์มืออาชีพต้องมีติดตัวไว้

รู้จักกับ AFTER Trigger และการนำไปใช้

AFTER Trigger (ตัวกระตุ้นหลังการทำงาน) เป็นประเภทที่นิยมใช้กันมากที่สุดตามชื่อของมันเลยครับ คือระบบจะทำงานหลังจากคำสั่ง Insert (เพิ่มข้อมูล), Update (แก้ไขข้อมูล) หรือ Delete (ลบข้อมูล) สำเร็จลงในตารางเรียบร้อยแล้ว เหมาะสำหรับงานประเภทการเก็บประวัติหรือการตรวจสอบข้อมูลย้อนหลัง

ตัวอย่างเช่น คุณต้องการเก็บประวัติว่าใครเข้ามาแก้ไขเงินเดือนพนักงานตอนไหนบ้าง คุณสามารถสร้าง Trigger ที่คอยดักจับเหตุการณ์ Update แล้วบันทึกค่าเก่าและค่าใหม่ลงในตารางประวัติทันที ตารางเสมือน (ตารางชั่วคราวที่เก็บข้อมูลก่อนและหลังเปลี่ยนแปลง) ที่ชื่อว่า inserted และ deleted จะถูกสร้างขึ้นมาให้เราใช้งานภายใน Trigger นี้โดยเฉพาะ

ข้อควรระวังคืออย่าใส่คำสั่งที่ซับซ้อนเกินไปใน Trigger เพราะทุกครั้งที่คุณสั่งงานตารางหลัก Trigger จะทำงานตามไปด้วย ถ้ามันทำงานช้าจะทำให้แอปพลิเคชันของคุณหน่วงตามไปด้วยเสมอ ให้เขียนเฉพาะงานที่จำเป็นจริงๆ เพื่อรักษาความเร็วของระบบ

-- สร้าง Trigger สำหรับบันทึกประวัติการแก้ไขข้อมูล
CREATE TRIGGER trg_LogSalaryChange
ON Employees
AFTER UPDATE
AS
BEGIN
    INSERT INTO SalaryHistory (EmployeeID, OldSalary, NewSalary, ChangeDate)
    SELECT d.EmployeeID, d.Salary, i.Salary, GETDATE()
    FROM deleted d
    JOIN inserted i ON d.EmployeeID = i.EmployeeID
END

คำอธิบายโค้ด: บรรทัดที่ 3 สร้าง Trigger ชื่อ trg_LogSalaryChange ผูกไว้กับตาราง Employees บรรทัดที่ 4 ระบุว่าให้ทำงานหลังเหตุการณ์ UPDATE บรรทัดที่ 7-10 คือการดึงข้อมูลจากตาราง deleted (ค่าก่อนแก้) และ inserted (ค่าหลังแก้) มาเก็บไว้ในตารางประวัติ

ผลลัพธ์ที่ควรเห็น: เมื่อคุณสั่ง UPDATE Employees SET Salary = 50000 WHERE ID = 1 ข้อมูลเงินเดือนเดิมและใหม่จะถูกเพิ่มเข้าไปในตาราง SalaryHistory โดยอัตโนมัติทันที

การทำงานของ INSTEAD OF Trigger

INSTEAD OF Trigger (ตัวกระตุ้นแทนที่การทำงาน) ทำงานต่างออกไป มันจะเข้าไปขัดขวางคำสั่งเดิมที่กำลังจะเกิดขึ้นแล้วทำสิ่งที่เขียนไว้แทนที่ ปกติเราใช้เมื่อต้องการดัดแปลงข้อมูลก่อนบันทึกจริง หรือใช้กับ View (ตารางจำลองที่สร้างจากคำสั่ง Query) ที่ไม่สามารถแก้ไขข้อมูลได้โดยตรง

ลองจินตนาการว่าคุณมีกฎว่าห้ามลบข้อมูลลูกค้าทิ้งจริงๆ แต่ให้เปลี่ยนสถานะเป็น "เลิกใช้งาน" แทน ในกรณีนี้ INSTEAD OF Trigger จะเข้ามาสวมรอยแทนคำสั่ง Delete ของผู้ใช้ แล้วเปลี่ยนเป็นการสั่ง Update สถานะแทน ทำให้ข้อมูลจริงในตารางยังคงอยู่ครบถ้วนตามความต้องการของธุรกิจ

การใช้ Trigger แบบนี้ต้องระวังเรื่องตรรกะให้ดี เพราะถ้าเขียนพลาดอาจทำให้คำสั่งบันทึกข้อมูลไม่ทำงานเลย หรือทำงานผิดพลาดไปจากที่ควรจะเป็น แนะนำให้ทดสอบในสภาพแวดล้อมจำลองจนมั่นใจก่อนนำไปใช้กับฐานข้อมูลจริงของลูกค้า

-- สร้าง Trigger แทนที่คำสั่งลบข้อมูล
CREATE TRIGGER trg_SoftDeleteCustomer
ON Customers
INSTEAD OF DELETE
AS
BEGIN
    UPDATE Customers 
    SET IsActive = 0 
    WHERE CustomerID IN (SELECT CustomerID FROM deleted)
END

คำอธิบายโค้ด: บรรทัดที่ 4 ระบุว่าให้ทำงาน INSTEAD OF DELETE คือแทนที่การลบ บรรทัดที่ 7-9 คือการเปลี่ยนสถานะ IsActive ของลูกค้าเป็น 0 แทนการลบแถวข้อมูลนั้นออกไปจริงๆ

ผลลัพธ์ที่ควรเห็น: เมื่อรันคำสั่ง DELETE FROM Customers WHERE CustomerID = 10 ข้อมูลแถวนั้นจะไม่หายไป แต่ค่าในคอลัมน์ IsActive จะเปลี่ยนจาก 1 เป็น 0 แทน

จัดการข้อผิดพลาดด้วย TRY...CATCH

ในการเขียนโปรแกรม Error Handling (การจัดการข้อผิดพลาด) เป็นสิ่งสำคัญมาก เพราะโปรแกรมที่ไม่มีการดักจับข้อผิดพลาดจะทำให้ระบบล่มหรือข้อมูลพังได้ง่ายๆ TRY...CATCH คือโครงสร้างมาตรฐานใน MS-SQL ที่ใช้ครอบโค้ดที่มีความเสี่ยงจะเกิดปัญหา

หลักการทำงานคือ เราจะเอาโค้ดที่อาจเกิดปัญหาไปวางไว้ในบล็อก BEGIN TRY หากโค้ดส่วนนั้นทำงานผิดพลาด ระบบจะกระโดดไปทำงานในบล็อก BEGIN CATCH ทันที ทำให้เราสามารถจัดการกับปัญหาที่เกิดขึ้นได้ เช่น การบันทึก Log หรือการแจ้งเตือนผู้ดูแลระบบ

การเขียนโปรแกรมที่ดีต้องคิดถึงกรณีที่เลวร้ายที่สุดเสมอ เช่น ถ้าฐานข้อมูลเต็ม หรือมีการส่งข้อมูลผิดประเภทเข้ามา ถ้าเราไม่ดักจับไว้ ระบบจะหยุดทำงานทันทีและสร้างความเสียหายต่อประสบการณ์ของผู้ใช้งาน

BEGIN TRY
    -- พยายามลบข้อมูลที่อาจไม่มีอยู่จริง
    DELETE FROM Orders WHERE OrderID = 999999
END TRY
BEGIN CATCH
    PRINT 'เกิดข้อผิดพลาดในการลบข้อมูล'
    PRINT ERROR_MESSAGE() -- แสดงข้อความแจ้งเตือนจากระบบ
END CATCH

คำอธิบายโค้ด: บรรทัดที่ 1-4 คือส่วนที่พยายามทำงาน บรรทัดที่ 5-8 คือส่วนที่ทำงานเมื่อเกิดข้อผิดพลาด ERROR_MESSAGE() เป็นฟังก์ชันที่บอกรายละเอียดว่าทำไมถึงรันไม่ผ่าน

ผลลัพธ์ที่ควรเห็น: หน้าจอแสดงผลข้อความ 'เกิดข้อผิดพลาดในการลบข้อมูล' และรายละเอียดของข้อผิดพลาดที่เกิดขึ้นจริง แทนที่จะเป็นหน้าจอแจ้งเตือน Error แบบดิบๆ ของระบบ

ยกระดับการจัดการด้วยคำสั่ง THROW

เมื่อเราเจอข้อผิดพลาดแล้ว การแค่พิมพ์ข้อความออกมาอาจไม่เพียงพอ บางครั้งเราต้องส่งสัญญาณบอกแอปพลิเคชันหลักว่าเกิดอะไรขึ้น THROW (คำสั่งโยนข้อผิดพลาด) ช่วยให้เราสามารถสร้าง Error ของเราเองขึ้นมาได้ เพื่อให้ระบบตรวจจับได้ชัดเจนว่านี่คือปัญหาที่ผู้เขียนโปรแกรมตั้งใจดักไว้

การใช้ THROW คู่กับ TRY...CATCH จะทำให้ระบบเราดูเป็นมืออาชีพมากขึ้น คุณสามารถกำหนดรหัสข้อผิดพลาดและข้อความที่สื่อสารกับทีมพัฒนาคนอื่นๆ ได้ชัดเจน เช่น ถ้าข้อมูลที่กรอกมาไม่ตรงตามเงื่อนไขธุรกิจ ให้ THROW ข้อความแจ้งเตือนกลับไปทันที

จำไว้ว่าการเขียนโค้ดไม่ใช่แค่ทำให้มันทำงานได้ แต่ต้องทำให้มันบอกได้ว่า "ทำไมมันถึงทำงานไม่ได้" เมื่อเกิดปัญหาขึ้นจริงๆ การมีระบบแจ้งเตือนที่ชัดเจนจะช่วยให้คุณประหยัดเวลาในการซ่อมแซมโค้ดได้มหาศาล

BEGIN TRY
    IF NOT EXISTS (SELECT * FROM Products WHERE Stock > 0)
        THROW 50001, 'สินค้าหมดสต็อก ไม่สามารถทำรายการได้', 1
END TRY
BEGIN CATCH
    PRINT 'พบปัญหา: ' + ERROR_MESSAGE()
END CATCH

คำอธิบายโค้ด: บรรทัดที่ 3 คือการตรวจสอบเงื่อนไขธุรกิจ บรรทัดที่ 4 คือการสั่ง THROW พร้อมรหัส 50001 และข้อความแจ้งเตือน ERROR_MESSAGE() ในบล็อก CATCH จะจับข้อความนี้มาแสดงผล

ผลลัพธ์ที่ควรเห็น: ระบบจะพิมพ์ข้อความ 'พบปัญหา: สินค้าหมดสต็อก ไม่สามารถทำรายการได้' ออกมา ทำให้รู้ทันทีว่าติดปัญหาที่จุดไหน

สรุป: การนำไปใช้จริงในงานพัฒนาซอฟต์แวร์

การเขียนโปรแกรมที่ดีต้องคำนึงถึงความปลอดภัยของข้อมูลเสมอ ทั้งการใช้ Trigger เพื่อตรวจสอบความถูกต้อง และการใช้ TRY...CATCH เพื่อป้องกันระบบล่ม การฝึกฝนเรื่องเหล่านี้ตั้งแต่เนิ่นๆ จะทำให้คุณเป็นโปรแกรมเมอร์ที่เขียนโค้ดได้อย่างรัดกุมและน่าเชื่อถือมากขึ้น

สมมติว่าคุณกำลังทำระบบร้านค้าออนไลน์ คุณควรใช้ Trigger ในการอัปเดตจำนวนสินค้าคงเหลือทันทีที่มีการสั่งซื้อ และใช้ THROW เพื่อแจ้งเตือนหากลูกค้ากดสั่งซื้อในขณะที่สินค้าหมด การทำแบบนี้จะช่วยให้ระบบของคุณจัดการข้อมูลได้แม่นยำแม้จะมีผู้ใช้งานจำนวนมากพร้อมกัน

เริ่มฝึกจากการสร้าง Trigger ง่ายๆ ในฐานข้อมูลส่วนตัวของคุณดูก่อน เมื่อคล่องแล้วค่อยลองเพิ่มระบบจัดการ Error เข้าไป การเป็นโปรแกรมเมอร์ที่เก่งไม่ได้วัดกันที่เขียนโค้ดเร็วแค่ไหน แต่วัดที่ว่าโค้ดของคุณพังยากแค่ไหนและแก้ไขได้รวดเร็วเพียงใดเมื่อมีปัญหาเกิดขึ้นครับ

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

คู่มือ MS-SQL Backup, Restore และการตั้งค่า Maintenance Plans สำหรับมือใหม่
MS-SQL

คู่มือ MS-SQL Backup, Restore และการตั้งค่า Maintenance Plans สำหรับมือใหม่

เรียนรู้วิธีสำรองข้อมูล (Backup) และกู้คืน (Restore) ฐานข้อมูล MS-SQL ด้วย SSMS พร้อมวิธีตั้งค่าระบบอัตโนมัติ เพื่อป้องกันข้อมูลหายสำหรับโปรแกรมเมอร์มือใหม่

3 weeks ago 7 นาที
14 views
คู่มือการจัดการความปลอดภัยใน MS-SQL: Logins, Users และการคุมสิทธิ์ด้วย GRANT, DENY, REVOKE
MS-SQL

คู่มือการจัดการความปลอดภัยใน MS-SQL: Logins, Users และการคุมสิทธิ์ด้วย GRANT, DENY, REVOKE

ไม่อยากให้ฐานข้อมูลถูกแฮกต้องอ่าน! เรียนรู้วิธีตั้งค่าความปลอดภัยใน MS-SQL ตั้งแต่การสร้าง Login (บัญชีผู้ใช้) ไปจนถึงการคุมสิทธิ์เข้าถึงข้อมูลให้ปลอดภัย

3 weeks ago 9 นาที
15 views
เจาะลึก MS-SQL User-Defined Functions (UDFs) วิธีสร้างฟังก์ชันใช้เองให้โค้ดสะอาดและจัดการง่าย
MS-SQL

เจาะลึก MS-SQL User-Defined Functions (UDFs) วิธีสร้างฟังก์ชันใช้เองให้โค้ดสะอาดและจัดการง่าย

อยากเขียน SQL ให้สั้นและจัดการง่ายขึ้นไหม? มาเรียนรู้การสร้างฟังก์ชันใช้เอง (UDFs) ทั้งแบบ Scalar และ Table-Valued เพื่อลดความซ้ำซ้อนและเพิ่มประสิทธิภาพให้ฐานข้อมูลกัน

3 weeks ago 8 นาที
16 views