如果我有如下所示的 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
中实现这一点?
我看到有一个 SQLAlchemy
CheckConstraint
对象 (see docs) , 但 MySQL
不支持检查约束。
数据模型在 SQLAlchemy
之外进行交互,因此最好是数据库级检查 (MySQL
)
最佳答案
好吧,考虑到您的要求“数据模型具有 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 ;
一些技巧和注意事项:
IF STATEMENT:为了避免检查每列不为空而其他为空的繁琐编写,我做了这个技巧:将每列减少到一个字符并检查有多少字符存在。请注意,如果
NEW.a
是Integer
、NULL
,则NEW.a-NEW.a
总是返回 1 个字符返回 0 个字符,操作NULL-NULL
在 MySQL 上返回NULL
。错误触发:我想你想引发一个错误,那么如何在 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 *test_id 的一个值不能为空` 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
关于python - 检查 SQLAlchemy 中互斥列的约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33906457/