PL/SQL ไม่ฟ้อง Error เพราะเราเผลอซ่อนมันไว้หรือเปล่า?
อย่าปล่อย WHEN OTHERS จบด้วย NULL; จัดการสิ่งที่จำเป็นแล้วส่ง exception ต่อ
PL/SQL ไม่ฟ้อง Error เพราะเราเผลอซ่อนมันไว้หรือเปล่า?
PL/SQL แจ้งว่าประมวลผลสำเร็จ แต่ข้างในทำงานผิดพลาดหรือเกิดข้อผิดพลาดค้างอยู่ได้หรือไม่? คำตอบคือ "ได้" หากในโค้ดมี Exception Handler คอยรับข้อผิดพลาดแล้วปล่อยให้ Block ทำงานจบเงียบ ๆ บทความนี้จะพามาทดลองคิวรีข้อมูลที่ไม่มีแถวตอบกลับ แล้วเปรียบเทียบผลลัพธ์ของการจัดการ Exception ทั้ง 3 รูปแบบกันครับ
Exception คือเหตุการณ์ผิดปกติที่เกิดขึ้นระหว่างการประมวลผล (Runtime Error) ส่วน Exception Handler คือบล็อกโค้ดที่เขียนไว้เพื่อจัดการกับเหตุการณ์นั้น โดยประโยคคำสั่ง WHEN OTHERS จะทำหน้าที่ดักจับ Exception ทุกประเภทที่ไม่ถูกจัดการโดย Handler เฉพาะก่อนหน้า

ภาพอธิบายแนวคิด: เปรียบเทียบตัวอย่าง handler ที่ซ่อน error กับแบบที่แสดงข้อความแล้ว RAISE กลับผู้เรียก DBMS_OUTPUT ไม่ใช่ persistent log
ขั้นที่ 1: ปล่อยให้ Exception ส่งไปถึงผู้เรียก (Default Behavior)
ทดลองเขียน PL/SQL Block โดยใส่เงื่อนไข WHERE 1 = 2 ซึ่งเป็นเท็จ ทำให้คำสั่ง SELECT ... INTO ไม่พบแถวข้อมูลในตาราง และไม่มีการใส่ Exception Handler:
DECLARE
l_value NUMBER;
BEGIN
SELECT 1 INTO l_value FROM dual WHERE 1 = 2;
END;
/
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
Help: https://docs.oracle.com/error-help/db/ora-01403/
วิเคราะห์ผลลัพธ์:
- ระบบส่งข้อผิดพลาด
ORA-01403: no data foundกลับมายังผู้เรียกทันที - รหัส
ORA-06512ทำหน้าที่ชี้ตำแหน่งบรรทัดของโค้ดใน Block ที่เกิดปัญหาขึ้นจริง
ขั้นที่ 2: ใส่ Handler ที่กลืน Error ไว้ (Anti-pattern: Swallowing Exceptions)
ทดลองใส่ WHEN OTHERS THEN NULL; เพื่อแสดงรูปแบบการซ่อนปัญหาที่ควรหลีกเลี่ยง:
DECLARE
l_value NUMBER;
BEGIN
SELECT 1 INTO l_value FROM dual WHERE 1 = 2;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/
PL/SQL procedure successfully completed.
วิเคราะห์ผลลัพธ์:
คำสั่ง SELECT ยังคงไม่พบข้อมูลเหมือนเดิม แต่ Client กลับแสดงข้อความว่า PL/SQL procedure successfully completed. เนื่องจากประโยคคำสั่ง WHEN OTHERS ได้ดักรับ Exception ไว้แล้วสั่ง NULL; (ไม่ทำอะไรเลย) ส่งผลให้โปรแกรมผู้เรียกเข้าใจผิดว่าการประมวลผลทำงานสำเร็จเรียบร้อย
ขั้นที่ 3: บันทึกข้อมูลข้อผิดพลาด แล้วส่ง Exception ต่อ (RAISE)
เปิดใช้งาน SERVEROUTPUT แล้วปรับแก้ Handler ให้พิมพ์ข้อความแจ้งเตือน ก่อนจะส่ง Exception เดิมกลับไปหาผู้เรียกด้วยคำสั่ง RAISE;:
SET SERVEROUTPUT ON
DECLARE
l_value NUMBER;
BEGIN
SELECT 1 INTO l_value FROM dual WHERE 1 = 2;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE || ': ' || SQLERRM);
RAISE;
END;
/
100: ORA-01403: no data found
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 8
ORA-06512: at line 4
Help: https://docs.oracle.com/error-help/db/ora-01403/
วิเคราะห์ผลลัพธ์:
- ข้อความจาก Handler แสดง
100: ORA-01403: no data foundออกมาทางหน้าจอ (หมายเหตุ:SQLCODEของNO_DATA_FOUNDใน PL/SQL คืนค่าเป็น100ตามมาตรฐาน ANSI SQL) - มีการส่งรหัสข้อผิดพลาด
ORA-01403พร้อม Stack Trace (ORA-06512) กลับไปยังโปรแกรมผู้เรียกตามปกติ ทำให้ซอฟต์แวร์ต้นทางรับรู้ความล้มเหลวได้อย่างถูกต้อง
สรุปแนวทางปฏิบัติที่ดีในการจัดการ Exception
- จัดการเฉพาะเหตุการณ์ที่คาดการณ์ไว้: หากกรณีหาข้อมูลไม่เจอ (
NO_DATA_FOUND) เป็นเงื่อนไขทางธุรกิจปกติ ให้ใช้ Handler เฉพาะ เช่นWHEN NO_DATA_FOUND THEN ...แล้วกำหนดค่าตอบกลับให้ชัดเจน - หลีกเลี่ยง
WHEN OTHERS THEN NULL;: คำสั่งนี้ถือเป็น Anti-pattern ร้ายแรง เพราะทำให้เกิดปัญหาซ่อนหมี (Silent Failure) ที่หาจุดผิดพลาดได้ยากมากในระบบ Production - จบ
WHEN OTHERSด้วยการ RAISE เสมอ: หากจำเป็นต้องใช้WHEN OTHERSเป็นด่านสุดท้ายเพื่อ Log ข้อมูล ควรจบด้วยคำสั่งRAISE;หรือRAISE_APPLICATION_ERROR()เพื่อให้ผู้เรียกรับรู้ถึงข้อผิดพลาดนั้นเสมอ DBMS_OUTPUTไม่ใช่ระบบ Log ถาวร: การใช้DBMS_OUTPUT.PUT_LINEช่วยแสดงผลระหว่างการทดสอบเท่านั้น แต่ไม่ได้ทำการบันทึกข้อมูลลง Table หรือ Log File ของแอปพลิเคชันจริงครับ อ่านหัวข้อ Oracle อื่นต่อได้ที่ บทความ Oracle บน teeDBA.com
บทความที่เกี่ยวข้อง

ต่อ Oracle ไม่ได้: Host, Port และ Service Name ต้องตรวจตรงไหน?
แยก Host, Port และ Service Name ใน Oracle Easy Connect พร้อมลำดับตรวจเมื่อ client เชื่อมต่อไม่ได้

UPDATE ค้างอยู่: จะรู้ได้อย่างไรว่ากำลังรอ Lock?
แยก session ที่รอกับ session ที่ถือ row lock และดูหลักฐานที่ DBA ควรเก็บก่อนจัดการ session

คอลัมน์เป็นข้อความ แต่เงื่อนไขเป็นตัวเลข: Oracle เปรียบเทียบอย่างไร?
ดูการเปรียบเทียบข้อความกับตัวเลขใน Oracle และเลือกชนิดข้อมูลให้ตรงก่อนแก้ query