I'm going to give two examples of how to do this using MySQL 8.0+. First for the alter statement to work if something exists it MUST be in a stored procedure. The example below shows how to drop and add a constraint if it exists or not already. If it doesn't exist it will simply ignore the if and create it. If it DOES exist it will drop it and then subsequently create it again. This is useful for debugging so you can quickly change your constraint logic and test it. For those that are new to DELIMITER, it essentially changes what would be the ; to $$ in this case. This is necessary so that the procedure knows the ; belong to it and not that the full SQL query is ending.
DROP PROCEDURE IF EXISTS trading.create_constraint;
DELIMITER $$
CREATE PROCEDURE trading.create_constraint()
BEGIN
IF EXISTS (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS WHERE CONSTRAINT_NAME = 'assigned_equity_percent_not_over_100')
THEN
ALTER TABLE Strategies DROP CONSTRAINT assigned_equity_percent_not_over_100;
END IF;
ALTER TABLE Strategies ADD CONSTRAINT assigned_equity_percent_not_over_100 CHECK (assigned_equity_percent <= 100 AND assigned_equity_percent>=0);
END$$
DELIMITER ;
CALL create_constraint();
Another example below, is how you can create a more advanced procedure with a trigger that will count the sum of all values and make sure they do not exceed 100 when updating or inserting by throwing an error via the SIGNAL SQLSTATE '45000' error.
DROP PROCEDURE IF EXISTS trading.check_sum_strategy_assigned_equity;
DELIMITER $$
CREATE PROCEDURE trading.check_sum_strategy_assigned_equity(IN new_equity_percentage DECIMAL(5,2),IN old_equity_percentage DECIMAL(5,2),IN updating BOOLEAN)
BEGIN
IF (updating=false) THEN
IF ((SELECT SUM(assigned_equity_percent) total FROM Strategies WHERE strategy_pack_id = strategy_pack_id)+new_equity_percentage)>100
THEN
SIGNAL SQLSTATE '45000' SET message_text = 'Can not INSERT a value of 100 for assigned equity percent with the given strategy_pack_id';
END IF;
ELSE
IF ((SELECT SUM(assigned_equity_percent) total FROM Strategies WHERE strategy_pack_id = strategy_pack_id)-old_equity_percentage+new_equity_percentage)>100
THEN
SIGNAL SQLSTATE '45000' SET message_text = 'Can not UPDATE a value of 100 for assigned equity percent with the given strategy_pack_id';
END IF;
END IF;
END$$
DELIMITER ;
DROP TRIGGER IF EXISTS ins_sum_strat_ass_eq;
CREATE TRIGGER ins_sum_strat_ass_eq
BEFORE INSERT ON Strategies
FOR EACH ROW
CALL trading.check_sum_strategy_assigned_equity(NEW.assigned_equity_percent,0.00,FALSE);
DROP TRIGGER IF EXISTS up_sum_strat_ass_eq;
CREATE TRIGGER up_sum_strat_ass_eq
BEFORE UPDATE ON Strategies
FOR EACH ROW
CALL trading.check_sum_strategy_assigned_equity(NEW.assigned_equity_percent,OLD.assigned_equity_percent,TRUE);
Something to note is that DELIMITER only works via MySQL client, not through the API's, so you will get errors saying that it does not recognize DELIMITER. To account for this you could run code something like what I did in javascript below.
//@JA - This function sanitizes custom SQL so that any delimiter code is removed which only works via client or phpmyadmin.
var sanitize_for_mysql = function(sql) {
sql = sql.replace(/([$][$])/gm, ";");
sql = sql.replace(/DELIMITER ;/gm, "");
return sql;
};
module.exports = sanitize_for_mysql;
By doing this you can still run this code using an ORM like Sequelize for example.