MySQL การใช้ Cursor ใน Stored Procedure เพื่อวนลูปประมวลผลข้อมูลทีละแถว

ในบางสถานการณ์ เราจำเป็นต้อง “อ่านข้อมูลจากหลายแถว” แล้วทำการประมวลผลทีละแถว เช่น

  • คำนวณยอดสะสมรายบุคคล
  • สร้างข้อความแจ้งเตือนเฉพาะลูกค้า
  • ส่งอีเมลแต่ละรายการจาก queue

กรณีแบบนี้ เราสามารถใช้ Cursor ใน Stored Procedure เพื่อช่วยวนลูปข้อมูลจาก SELECT ทีละแถวได้

Cursor คืออะไร?

Cursor คือเครื่องมือใน MySQL สำหรับ “เลื่อนอ่าน” ข้อมูลจากผลลัพธ์ของ SELECT ทีละแถว ทำงานคล้ายกับการวนลูป array ในภาษาโปรแกรม เช่น foreach, for, while

โครงสร้างพื้นฐานของ Cursor

SQL
DECLARE cursor_name CURSOR FOR SELECT_statement;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

OPEN cursor_name;
READ_LOOP: LOOP
  FETCH cursor_name INTO var1, var2, ...;
  IF done THEN
    LEAVE READ_LOOP;
  END IF;

  -- คำสั่งที่ต้องการทำกับแต่ละแถว

END LOOP;
CLOSE cursor_name;

ตัวอย่างการใช้งาน

คำนวณยอดรวมของลูกค้าทุกคน แล้วบันทึกลงตาราง customer_totals

สมมติว่าเรามีตารางชื่อ payments ซึ่งเก็บข้อมูลดังนี้

customer_idamountstatus
1200.00paid
2150.00paid
1100.00paid
380.00paid

และมีตาราง customer_totals ซึ่งเก็บข้อมูลดังนี้

customer_idtotal_payment
1300.00
2150.00
380.00

สร้าง Stored Procedure

SQL
DELIMITER //

CREATE PROCEDURE calculate_customer_totals()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE cid INT;
  DECLARE total DECIMAL(10,2);

  DECLARE cur CURSOR FOR
    SELECT customer_id, SUM(amount)
    FROM payments
    WHERE status = 'paid'
    GROUP BY customer_id;

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cur;

  read_loop: LOOP
    FETCH cur INTO cid, total;
    IF done THEN
      LEAVE read_loop;
    END IF;

    INSERT INTO customer_totals(customer_id, total_payment)
    VALUES (cid, total);
  END LOOP;

  CLOSE cur;
END //

DELIMITER ;

เรียกใช้งาน

SQL
CALL calculate_customer_totals();

ผลลัพธ์

customer_idtotal_payment
1300.00
2150.00
380.00

หมายเหตุ

  • ต้องประกาศ DECLARE CURSOR และ DECLARE HANDLER ก่อน OPEN
  • CONTINUE HANDLER ช่วยป้องกัน error เมื่อ FETCH แล้วไม่เจอข้อมูล
  • การลืมปิด Cursor (CLOSE) อาจทำให้เกิด memory leak ในระบบที่ใช้บ่อย
แชร์เรื่องนี้