MySQL:如何防止插入所有列= NULL的行?

时间:2010-10-04 09:16:26

标签: mysql null definition

在我的MySQL表中,每列本身都可以为NULL,但必须至少有一列具有非NULL值。目前,我将一个insert语句包装在一个存储过程中,该过程会阻止插入所有NULL行,但这当然不会阻止任何人使用本机INSERT语句,从而绕过我的包装程序。

是否存在使用该约束定义表的“本机”方式?

3 个答案:

答案 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错误时。