我将给出两个例子来说明如何使用 MySQL 8.0+ 来做到这一点。首先,如果存在某些东西,alter 语句才能工作,它必须在存储过程中。下面的示例显示了如何删除和添加约束(如果存在或不存在)。如果它不存在,它将简单地忽略 if 并创建它。如果它确实存在,它将删除它,然后再次创建它。 这对于调试很有用,因此您可以快速更改约束逻辑并对其进行测试。对于那些不熟悉 DELIMITER 的人来说,它从本质上改变了 ; 在这种情况下为 $$。这是必要的,以便程序知道; 属于它,而不是完整的 SQL 查询正在结束。
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();
下面的另一个示例是如何使用触发器创建更高级的过程,该触发器将计算所有值的总和,并通过 SIGNAL SQLSTATE '45000' 错误引发错误来确保在更新或插入时它们不超过 100。
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);
需要注意的是,DELIMITER 只能通过 MySQL 客户端工作,而不是通过 API,所以你会收到错误,说它不能识别 DELIMITER。为了解决这个问题,您可以运行类似于我在下面的 javascript 中所做的代码。
//@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;
通过这样做,您仍然可以使用诸如 Sequelize 之类的 ORM 运行此代码。