MariaDB 10.3.6中CHECK约束无法使用自定义函数的解决问询
解决MariaDB 10.3.6中CHECK约束无法使用自定义函数的问题
你遇到的问题是因为MariaDB从10.2.1版本开始真正强制执行CHECK约束,但同时限制了CHECK子句中不能使用自定义函数;而10.1版本虽然允许解析CHECK约束,但实际上不会执行验证,所以之前没报错但约束没效果。下面给你两种可行的替代方案:
方案一:将正则表达式直接嵌入CHECK约束
既然自定义函数的核心是正则验证,我们可以把正则表达式直接写到CHECK子句里,这样既符合MariaDB的限制,又能实现验证逻辑。
修改后的ALTER TABLE语句如下:
-- 添加主键 alter table usuarios add constraint pk_usuarios primary key (cedula); -- 验证cedula范围 alter table usuarios add constraint ck_cedula check (500000 <= cedula and cedula <= 10000000); -- 验证contraseña只能包含字母数字 alter table usuarios add constraint ck_contraseña check (contraseña regexp '^[[:alnum:]]*$'); -- 验证nombre可以是单个单词或带空格的多个单词(修正了你原正则里多余的空格) alter table usuarios add constraint ck_nom_usuario check (nombre regexp '^[[:alpha:]]*$|^[[:alpha:]]+ [[:alpha:]]*$'); -- 验证apellido同nombre规则 alter table usuarios add constraint ck_apell_usuario check (apellido regexp '^[[:alpha:]]*$|^[[:alpha:]]+ [[:alpha:]]*$');
这种方案的优势是简洁高效,直接利用MariaDB内置的REGEXP函数,不需要额外维护自定义函数。
方案二:使用触发器实现验证
如果你的验证逻辑比较复杂,或者需要复用验证逻辑,触发器是更灵活的选择——触发器中可以调用自定义函数,并且能在插入/更新数据前执行验证。
首先保留你原来的自定义函数(如果需要的话),然后创建触发器:
-- 验证contraseña的触发器 delimiter // create trigger trg_usuarios_check_contraseña before insert on usuarios for each row begin if contr_usuario(new.contraseña) != 1 then signal sqlstate '45000' set message_text = 'Contraseña debe contener solo letras y números'; end if; end // create trigger trg_usuarios_update_contraseña before update on usuarios for each row begin if contr_usuario(new.contraseña) != 1 then signal sqlstate '45000' set message_text = 'Contraseña debe contener solo letras y números'; end if; end // -- 验证nombre的触发器 create trigger trg_usuarios_check_nombre before insert on usuarios for each row begin if nom_apell_usuario(new.nombre) != 1 then signal sqlstate '45000' set message_text = 'Nombre debe contener solo letras o letras con espacios'; end if; end // create trigger trg_usuarios_update_nombre before update on usuarios for each row begin if nom_apell_usuario(new.nombre) != 1 then signal sqlstate '45000' set message_text = 'Nombre debe contener solo letras o letras con espacios'; end if; end // -- 验证apellido的触发器 create trigger trg_usuarios_check_apellido before insert on usuarios for each row begin if nom_apell_usuario(new.apellido) != 1 then signal sqlstate '45000' set message_text = 'Apellido debe contener solo letras o letras con espacios'; end if; end // create trigger trg_usuarios_update_apellido before update on usuarios for each row begin if nom_apell_usuario(new.apellido) != 1 then signal sqlstate '45000' set message_text = 'Apellido debe contener solo letras o letras con espacios'; end if; end // delimiter ;
触发器会在插入或更新数据前执行验证,如果不符合规则就抛出自定义错误信息,阻止操作。
方案对比
- 方案一:适合简单的验证逻辑,性能更好,维护成本低,推荐优先使用。
- 方案二:适合复杂或需要复用的验证逻辑,灵活性更高,但需要维护多个触发器。
内容的提问来源于stack exchange,提问作者chelo
相关产品推荐
相关产品推荐

