【问题标题】:Check constraint for mutually exclusive columns in SQLAlchemy检查 SQLAlchemy 中互斥列的约束
【发布时间】:2016-02-27 15:35:39
【问题描述】:

如果我有一个如下所示的 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 外键存在,我如何在 SQLAlchemy 中实现这一点?

我看到有SQLAlchemyCheckConstraint对象(see docs),但是MySQL不支持检查约束。

数据模型在SQLAlchemy 之外有交互,所以最好是数据库级检查 (MySQL)

【问题讨论】:

标签: python mysql sqlalchemy


【解决方案1】:

好吧,考虑到您的要求“数据模型在 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. IF STATEMENT:为了避免检查每列不为空而其他为空的繁琐编写,我做了这个技巧:将每一列减少为一个字符并检查多少字符存在。请注意,如果NEW.aIntegerNEW.a-NEW.a 总是返回 1 个字符,NULL 返回 0 个字符,并且操作 NULL-NULL 在 MySQL 上返回 NULL

  2. ERROR TRIGGERING:我想你想引发一个错误,那么如何在 MySQL 上做到这一点?你没有提到MySQL版本。只有on MySQL 5.5 you can use the SIGNAL syntax to throw an exception。所以更便携的方法是发出一个无效的语句,如: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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多