0
votes

here is what im trying to do:

Table called departments has many-to-many relation with table called employees. so, table department_employees has columns: department_id, employee_id, is_active.

indexed department_id, employee_id as pk.

I get a string of employees ids like '12,15,18,19'. I get the department id.

I call a Mysql stored procedure (routine) that should:

  • insert all the employees to the department
  • if they exist and NOT active than activate
  • all the other employees should be deactivated

CREATE PROCEDURE (IN @dep_id INT, IN @emp_ids TEXT)

INSERT INTO TBL_DEPARTMENT_EMPLOYEES (DEPARTMENT_ID, EMPLOYEE_ID, IS_ACTIVE) SELECT @dep_id, EMPLOYEE_ID, 1 FROM TBL_EMPLOYEES WHERE FIND_IN_SET(EMPLOYEE_ID, @emp_ids) ON DUPLICATE KEY UPDATE IS_ACTIVE=1;

UPDATE TBL_DEPARTMENT_EMPLOYEES SET IS_ACTIVE=0 WHERE DEPARTMENT_ID=@dep_id AND NOT FIND_IN_SET(EMPLOYEE_ID, @emp_ids);

only the first query runs and i guess the second one cant because of locking or something, i tried the TRANSACTION - COMMIT trick, didnt work. I thought maybe one of the awesome guys here can help or eben make it all run in a single query. thanks!

1

1 Answers

2
votes

This procedure is not pretty, but its the best I can come up with given the concatenated IDs. It should also work faster than the FIND_IN_SET solution, because it can use the index on EMPLOYEE_ID.

CREATE PROCEDURE `test`(IN `dep_id` INT, IN `emp_ids` TEXT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    MODIFIES SQL DATA
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
START TRANSACTION;
IF(emp_ids REGEXP '^[0-9,]+$') THEN #this will NOT guarantee a valid query but will prevent injections
    UPDATE TBL_DEPARTMENT_EMPLOYEES SET IS_ACTIVE=0 WHERE DEPARTMENT_ID=dep_id;
    SET @q = CONCAT('
        INSERT INTO TBL_DEPARTMENT_EMPLOYEES (DEPARTMENT_ID, EMPLOYEE_ID, IS_ACTIVE) 
        SELECT ?, EMPLOYEE_ID, 1 
        FROM TBL_EMPLOYEES 
        WHERE EMPLOYEE_ID IN (',emp_ids,')
        ON DUPLICATE KEY UPDATE IS_ACTIVE=1;
    '); 
    PREPARE stmt1 FROM @q;
    SET @dep_id = dep_id;
    EXECUTE stmt1 USING @dep_id;
    DEALLOCATE PREPARE stmt1;
END IF;
COMMIT;
END ;