CREATE FUNCTION คืนค่า Average แบบ Conditional
MySQL User-Defined Function (UDF) สามารถ Return ค่า Scalar ได้ ใช้ DETERMINISTIC เพื่อบอก Optimizer ว่า Same Input = Same Output
ตัวอย่าง: หาค่าเฉลี่ย Marks ของ John
CREATE TABLE DemoTable638 (Name VARCHAR(100), Marks INT);
INSERT INTO DemoTable638 VALUES
('John', 67), ('John', 90), ('David', 99), ('John', 60);
สร้าง Function
SET GLOBAL log_bin_trust_function_creators = 1; -- ต้องการสำหรับ Binary Logging
DELIMITER //
CREATE FUNCTION getAverageDemo()
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE avg_val INT;
SELECT AVG(Marks) INTO avg_val
FROM DemoTable638
WHERE Name = 'John';
RETURN avg_val;
END //
DELIMITER ;
เรียกใช้ Function
SELECT getAverageDemo();
ผลลัพธ์: 72 ( (67+90+60)/3 = 72.33 → INT = 72 )
Function Parameters (ยืดหยุ่นกว่า)
CREATE FUNCTION getAverageByName(p_name VARCHAR(100))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
DECLARE avg_val DECIMAL(10,2);
SELECT AVG(Marks) INTO avg_val
FROM DemoTable638
WHERE Name = p_name;
RETURN COALESCE(avg_val, 0);
END;
การใช้งาน:
SELECT getAverageByName('John'); -- 72.33
SELECT getAverageByName('David'); -- 99.00
SELECT getAverageByName('Unknown'); -- 0.00
⚠️ ข้อจำกัดและ Best Practices
- log_bin_trust_function_creators = 1 - จำเป็นถ้า Binary Logging เปิดอยู่
- DETERMINISTIC / NO SQL / READS SQL DATA - ต้องระบุอย่างน้อย 1 ตัว
- ไม่ควรใช้ใน WHERE/JOIN บนตารางใหญ่ - เรียกต่อ Row ช้ามาก
- ไม่สามารถใช้ Dynamic SQL (PREPARE/EXECUTE) ใน Function
- Transaction Control ไม่ได้ (ไม่มี COMMIT/ROLLBACK)
Performance: Function vs Inline Query
-- Function: เรียกต่อ Row (ช้า)
SELECT getAverageByName(name) FROM users;
-- Inline: Single Scan (เร็ว)
SELECT name, AVG(marks) OVER (PARTITION BY name) FROM scores;
-- หรือ Group By
SELECT name, AVG(marks) FROM scores GROUP BY name;
MySQL 8.0: Window Functions แทน Function
SELECT
Name,
Marks,
AVG(Marks) OVER (PARTITION BY Name) AS avg_marks
FROM DemoTable638;