Либо ИЛИ ненулевые ограничения в MySQL

Какой лучший способ создать ограничение в NULL в MySQL, так что fieldA и fieldB не могут быть равны NULL. Мне все равно, является ли один из них NULL сам по себе, до тех пор, пока другое поле имеет значение, отличное от NULL. И если они оба имеют значения, отличные от NULL, то это еще лучше.

Ответ 1

MySQL 5.5 представил SIGNAL, поэтому нам больше не нужен дополнительный столбец в Билле Карвине. Билл указал, что вам также нужен триггер для обновления, поэтому я тоже включил его.

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

Ответ 2

@Sklivvz: тестирование с MySQL 5.0.51a, я нахожу, что он анализирует ограничение CHECK, но не применяет его. Я могу вставить (NULL, NULL) без ошибок. Протестировано как MyISAM, так и InnoDB. Впоследствии использование SHOW CREATE TABLE показывает, что ограничение CHECK не указано в определении таблицы, хотя при определении таблицы не было ошибок.

Это соответствует руководству MySQL, в котором говорится: "Предложение 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

Вам также нужен аналогичный триггер ПЕРЕД ОБНОВЛЕНИЕМ.

Ответ 3

Это не ответ на ваш вопрос, а дополнительная информация.

Когда вы работаете с несколькими столбцами и проверяете, все ли они null или один не является нулевым, я обычно использую 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

Это может использоваться в вашем триггере.

Ответ 4

Это стандартный синтаксис для такого ограничения, но MySQL блаженно игнорирует ограничение впоследствии

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

Ответ 5

Я сделал что-то подобное в SQL Server, я не уверен, будет ли он работать непосредственно в MySQL, но:

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

По крайней мере, я считаю, что синтаксис.

Однако имейте в виду, что вы не можете создавать контрольные ограничения в таблицах, вы можете проверять столбцы только в одной таблице.