在我的MySQL表中,每列本身都可以为NULL,但必须至少有一列具有非NULL值。目前,我将一个insert语句包装在一个存储过程中,该过程会阻止插入所有NULL行,但这当然不会阻止任何人使用本机INSERT语句,从而绕过我的包装程序。
是否存在使用该约束定义表的“本机”方式?
答案 0 :(得分:3)
仅授予执行权限,以便用户或您的应用程序用户只能调用存储过程!
答案 1 :(得分:2)
添加简单的检查约束
CHECK(COALESCE(Field1, Field2, ... FieldN) IS NOT NULL)
更新:
发现mysql不支持检查约束(解析,但忽略),一种可能的解决方法:使用trigger(查看http://db4free.blogspot.com/2006/01/emulating-check-constraints.html)
答案 2 :(得分:2)
由于MySQL不强制执行检查约束,您可能希望使用触发器模拟一个。我建议查看这篇MySQL Forge文章:
这个想法是将检查逻辑移动到触发器。如果检查失败,请通过引发唯一密钥违规来调用失败的存储过程。这允许我们将描述性错误消息返回给客户端。
你的触发器可能看起来像这样:
DELIMITER $$
CREATE TRIGGER check_not_all_null BEFORE INSERT ON your_table FOR EACH ROW
BEGIN
IF COALESCE(field_1, field_2, field_3) IS NOT NULL THEN
CALL fail('All fields cannot be null');
END IF;
END $$
DELIMITER ;
我们需要使fail
sproc引发唯一的密钥违规,以便在检查失败时中止INSERT
。上面提到的文章建议创建一个如下定义的内存表:
CREATE TABLE `Error` (
`ErrorGID` int(10) unsigned NOT NULL auto_increment,
`Message` varchar(128) default NULL,
`Created` timestamp NOT NULL default CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`ErrorGID`),
UNIQUE KEY `MessageIndex` (`Message`)
) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
然后fail
sproc可以按如下方式实现:
DELIMITER $$
CREATE PROCEDURE `fail`(_message VARCHAR(128))
BEGIN
INSERT INTO error (message) VALUES (_message);
INSERT INTO error (message) VALUES (_message);
END$$
DELIMITER ;
双INSERT
将确保引发唯一键违规。如果表中已存在相同的消息,则会在第一个INSERT
上引发违规,但只要失败就无所谓。
我们可以从命令行尝试fail
sproc:
mysql> CALL fail('All fields cannot be null');
ERROR 1062 (23000): Duplicate entry 'All fields cannot be null' for key 2
好消息是我们收到了一条可读的错误消息。但是我们没有找回正确的错误代码,而且我们没有真正的“重复条目”。这显然是此方法的一个限制,尤其是在使用错误处理的过程中更新或插入记录时,特别是在处理1062 Duplicate Entry
错误时。