Проверить ограничение для взаимоисключающих столбцов в SQLAlchemy

Если у меня есть декларативная модель SQLAlchemy, как показано ниже:

class Test(Model): __tablename__ = 'tests' id = Column(Integer, Sequence('test_id_seq'), primary_key=True) ... Atest_id = Column(Integer, ForeignKey('Atests.id'), nullable=True) Btest_id = Column(Integer, ForeignKey('Btests.id'), nullable=True) Ctest_id = Column(Integer, ForeignKey('Ctests.id'), nullable=True) Dtest_id = Column(Integer, ForeignKey('Dtests.id'), nullable=True) Etest_id = Column(Integer, ForeignKey('Etests.id'), nullable=True) ... date = Column(DateTime) status = Column(String(20)) # pass, fail, needs_review 

И я хотел бы убедиться, что в заданной строке присутствует только один из *test_id внешних ключей *test_id , как я могу это сделать в SQLAlchemy ?

Я вижу, что есть объект SQLAlchemy CheckConstraint (см. CheckConstraint ) , но MySQL не поддерживает проверки ограничений.

Модель данных имеет взаимодействие вне SQLAlchemy , поэтому желательно, чтобы это была проверка уровня базы данных ( MySQL )

One Solution collect form web for “Проверить ограничение для взаимоисключающих столбцов в SQLAlchemy”

Ну, учитывая ваши реквизиты «Модель данных имеет взаимодействие вне SQLAlchemy, поэтому желательно, чтобы это была проверка уровня базы данных (MySQL)» и «убедитесь, что только один [..] не является нулевым» . Я думаю, что лучший подход – написать триггер следующим образом:

 DELIMITER $$ CREATE TRIGGER check_null_insert BEFORE INSERT ON my_table FOR EACH ROW BEGIN IF CHAR_LENGTH(CONCAT_WS('', NEW.a-NEW.a, NEW.b-NEW.b, NEW.c-NEW.c)) = 1 THEN UPDATE `Error: Only one value of *test_id must be not null` SET z=0; END IF; END$$ DELIMITER ; 

Некоторые трюки и соображения:

  1. ЕСЛИ ЗАЯВЛЕНИЕ : во избежание утомительной записи проверки каждый столбец не является нулевым, а другие равны нулю, я сделал этот трюк: уменьшите каждый столбец до одного символа и проверьте, сколько символов существует. Обратите внимание, что NEW.a-NEW.a всегда возвращает 1 символ, если NEW.a является Integer , NULL возвращает 0 символов, а операция NULL-NULL возвращает NULL в MySQL.

  2. ERROR TRIGGERING : Я предполагаю, что вы хотите поднять ошибку, и как это сделать в MySQL? Вы не упомянули версию MySQL. Только для MySQL 5.5 вы можете использовать синтаксис SIGNAL для генерирования исключения . Таким образом, более переносимый способ выдает недопустимый оператор: UPDATE xx SET z=0 . Если вы используете MySQL 5.5, вы можете использовать: signal sqlstate '45000' set message_text = 'Error: Only one value of *test_id must be not null'; вместо UPDATE `Error: Only one value of *test_id must be not null` SET z=0;

Кроме того, я думаю, вы тоже хотите проверить это на обновлениях, поэтому используйте:

 DELIMITER $$ CREATE TRIGGER check_null_update BEFORE UPDATE ON my_table FOR EACH ROW BEGIN IF CHAR_LENGTH(CONCAT_WS('', NEW.a-NEW.a, NEW.b-NEW.b, NEW.c-NEW.c)) = 1 THEN UPDATE `Error: Only one value of *test_id must be not null` SET z=0; END IF; END$$ DELIMITER ; 

Или создайте хранимую процедуру и вызовите ее.

Обновить

Для баз данных, которые поддерживают контрольные ограничения , код более прост, см. Этот пример для SQL Server :

 CREATE TABLE MyTable (col1 INT NULL, col2 INT NULL, col3 INT NULL); GO ALTER TABLE MyTable ADD CONSTRAINT CheckOnlyOneColumnIsNull CHECK ( LEN(CONCAT(col1-col1, col2-col2, col3-col3)) = 1 ) GO 
  • Запрос с функцией в модели Flask-SQLAlchemy дает объекту BaseQuery не вызываемую ошибку
  • Удаление строки с помощью Flask-SQLAlchemy
  • SQLAlchemy с count, group_by и order_by с использованием ORM
  • Как получить строки, которые соответствуют списку 3-х кортежей с SQLAlchemy
  • SQLAlchemy - использование 'aliased' в запросе с пользовательским отношением primaryjoin
  • одно поле с различными типами данных
  • Как подключить базу данных MySQL с помощью Python + SQLAlchemy удаленно?
  • sqlalchemy date как строка в raw sql
  • Python - лучший язык программирования в мире.