MySQL中的OR非空约束

时间:2008-10-04 15:14:29

标签: sql mysql null

在MySQL中创建非NULL约束的最佳方法是,fieldA和fieldB不能都为NULL。我不关心其中任何一个本身是NULL,只要其他字段具有非NULL值。如果它们都具有非NULL值,那么它甚至更好。

6 个答案:

答案 0 :(得分:8)

这不是您问题的直接答案,而是一些其他信息。

当处理多个列并检查是否所有列都为空或者一个不为空时,我通常使用COALESCE() - 如果列表增长,它的简短,可读且易于维护:

COALESCE(a, b, c, d) IS NULL -- True if all are NULL

COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null

这可以在您的触发器中使用。

答案 1 :(得分:7)

@Sklivvz:使用MySQL 5.0.51a进行测试,我发现它解析了CHECK约束,但没有强制执行。我可以插入(NULL,NULL)而没有错误。测试了MyISAM和InnoDB。随后使用SHOW CREATE TABLE显示CHECK约束不在表定义中,即使我在定义表时没有给出错误。

这匹配MySQL manual,其中说:“CHECK子句被解析但被所有存储引擎忽略。”

因此,对于MySQL,您必须使用触发器来强制执行此规则。唯一的问题是MySQL触发器无法引发错误或中止INSERT操作。在触发器中可以做的一件事就是将NOT NULL列设置为NULL。

CREATE TABLE foo (
  FieldA INT,
  FieldB INT,
  FieldA_or_FieldB TINYINT NOT NULL;
);

DELIMITER //
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SET NEW.FieldA_or_FieldB = NULL;
  ELSE
    SET NEW.FieldA_or_FieldB = 1;
  END IF;
END//

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error

在更新之前,您还需要一个类似的触发器。

答案 2 :(得分:5)

MySQL 5.5引入了SIGNAL,因此我们不再需要Bill Karwin的答案中的额外列。比尔指出你还需要一个更新触发器,所以我也把它包括在内。

CREATE TABLE foo (
  FieldA INT,
  FieldB INT
);

DELIMITER //
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
  END IF;
END//
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
  END IF;
END//
DELIMITER ;

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
UPDATE foo SET FieldA = NULL; -- gives error

答案 3 :(得分:4)

这是这种约束的标准语法,但MySQL后来幸福地忽略了约束

ALTER TABLE `generic` 
ADD CONSTRAINT myConstraint 
CHECK (
  `FieldA` IS NOT NULL OR 
  `FieldB` IS NOT NULL
) 

答案 4 :(得分:2)

我在SQL Server中做过类似的事情,我不确定它是否可以直接在MySQL中运行,但是:

ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );

至少我相信这就是语法。

但是,请记住,不能跨表创建检查约束,只能检查一个表中的列。

答案 5 :(得分:0)

我使用带有 COALESCE ... NOT NULLGENERATED ALWAYS 列来完成此操作:

DROP TABLE IF EXISTS `error`;

CREATE TABLE IF NOT EXISTS `error` (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    left_id BIGINT UNSIGNED NULL,
    right_id BIGINT UNSIGNED NULL,
    left_or_right_id BIGINT UNSIGNED GENERATED ALWAYS AS (COALESCE(left_id, right_id)) NOT NULL,
    when_occurred TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    message_text LONGTEXT NOT NULL,
    INDEX id_index (id),
    INDEX when_occurred_index (when_occurred),
    INDEX left_id_index (left_id),
    INDEX right_id_index (right_id)
);

INSERT INTO `error` (left_id, right_id, message_text) VALUES (1, 1, 'Some random text.');  -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (null, 1, 'Some random text.'); -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (1, null, 'Some random text.'); -- Ok.
INSERT INTO `error` (left_id, right_id, message_text) VALUES (null, null, 'Some random text.'); -- ER_BAD_NULL_ERROR: Column 'left_or_right_id' cannot be null

在 MySQL 8.0.22 版上