mysqlfunctioncursors

How to properly write a cursor inside a function?


I require your help because I'm kind of lost. I tried to look over google for cursors in functions and references about those but I can't seem to quite wrap my head the concept. I have a homework where I need to :

This is what i've made so far...

Can you help me out with the problem with hint or at least simple examples/ressources of cursors in functions so get I can start get a better hold of the concept.

DROP FUNCTION IF EXISTS Program;
DELIMITER //
CREATE FUNCTION Program(IncSal DECIMAL(3,2))
RETURNS DECIMAL(8,2)
DETERMINISTIC
    BEGIN
        DECLARE Salaire DECIMAL (8,2);
        DECLARE end BOOLEAN DEFAULT FALSE;
        DECLARE CurSalary CURSOR FOR
            SELECT Sala_EMPL
                        FROM EMPLOYE;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET end = TRUE;      

        OPEN CurSalary;
            loop_cursor: LOOP
                IF end THEN 
                    LEAVE loop_cursor; 
                END IF;
                UPDATE EMPLOYE
                SET Sala_EMPL=(Sala_EMPL*IncSal);
            END LOOP;
        CLOSE CurSalary;

        RETURN AVG(CurSalary);
    END; 
    //
    DELIMITER ;

Solution

  • If you use a cursor you have to FETCH from the cursor (please review https://dev.mysql.com/doc/refman/8.0/en/fetch.html) without a fetch the loop is infinite. AVG is an aggregate function , you cannot AVG over a cursor (you need a select..from). Your update statement will apply to all employees every time you iterate a cursor loop (logically absurd). Personally I would never use a function because what you are trying to do is not really appropriate in a function (i would use a procedure).

    an example of a 'working' but wrong function

    DROP FUNCTION IF EXISTS f;
    DELIMITER //
    CREATE FUNCTION f(IncSal DECIMAL(3,2))
    RETURNS DECIMAL(8,2)
    DETERMINISTIC
        BEGIN
            DECLARE Salaire DECIMAL (8,2);
            DECLARE end BOOLEAN DEFAULT FALSE;
            DECLARE CurSalary CURSOR FOR
            SELECT salary FROM EMPLOYEe;
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET end = TRUE;      
    
            OPEN CurSalary;
                loop_cursor: LOOP
                     fetch cursalary into salaire;
                    IF end THEN 
                        LEAVE loop_cursor; 
                    END IF;
                    UPDATE EMPLOYEe
                                SET Salary=salary + (salary*incsal);
                END LOOP;
            CLOSE CurSalary;
    
            #RETURN AVG(CurSalary);
            return (select avg(salary) from employee);
        END; 
        //
        DELIMITER ;
    
    MariaDB [sandbox]> select * from employee;
    +------------+-----------+--------------+--------+
    | employeeid | firstname | departmentid | salary |
    +------------+-----------+--------------+--------+
    |          1 | aaa       |            1 |  10000 |
    |          2 | bbb       |            2 |  10000 |
    |          3 | ccc       |            3 |  10000 |
    +------------+-----------+--------------+--------+
    3 rows in set (0.00 sec)
    
    MariaDB [sandbox]>
    MariaDB [sandbox]>     select f(.05);
    +----------+
    | f(.05)   |
    +----------+
    | 11576.00 |
    +----------+
    1 row in set (0.00 sec)
    
    MariaDB [sandbox]>
    MariaDB [sandbox]>     select * from employee;
    +------------+-----------+--------------+--------+
    | employeeid | firstname | departmentid | salary |
    +------------+-----------+--------------+--------+
    |          1 | aaa       |            1 |  11576 |
    |          2 | bbb       |            2 |  11576 |
    |          3 | ccc       |            3 |  11576 |
    +------------+-----------+--------------+--------+
    3 rows in set (0.00 sec)