我有一个表,我用它来定义客户端的默认和自定义选项。如果custom_id
字段有一个值,那么它代表一个唯一的自定义作业的记录。如果它是空的,那么记录代表客户端的默认选项。
我的问题是,我想在两种情况下强制唯一性:
custom_id
、client
和option
均为非空值client
和option
是非空的,但custom_id
为空
下面的表定义在第一种情况下有效,但在第二种情况下无效,因为null不被视为值。有没有一种方法可以使null被视为值?
class OptionTable(Base):
__tablename__ = "option_table"
__table_args__ = (
UniqueConstraint("custom", "client", "option", name="uix_custom_client_option"),
)
id = Column(Integer, primary_key=True)
custom_id = Column(Integer, ForeignKey("custom.id"), nullable=True)
client = Column(String, nullable=False)
option = Column(String, nullable=False)
字符串
下面是一些示例数据和按顺序添加时的结果:
+----+----------+----------+--------+---------------------------------------------+
| id | CustomID | Client | Option | result |
+----+----------+----------+--------+---------------------------------------------+
| 1 | 123 | MegaCorp | Apple | OK |
| 2 | 123 | MegaCorp | Apple | not unique |
| 3 | NULL | MegaCorp | Apple | OK |
| 4 | NULL | MegaCorp | Google | OK |
| 5 | NULL | MegaCorp | Google | this one should fail, but currently doesn't |
+----+----------+----------+--------+---------------------------------------------+
型
这个related answer做了我正在寻找的,使用MySQL。理想的解决方案是使用sqlalchemy。
4条答案
按热度按时间brvekthn1#
根据this answer中推荐的方法,解决方案是创建两个partial indexes。
使用sqlalchemy作为问题中的例子,看起来像:
字符串
ndh0cuux2#
我会做
字符集
其中,
-42
是一个值,对于custom_id
,该值不能出现。它是如何产生作用的?
如果有两行具有相同的
client
、option
和custom_id
,并且都是NOT NULL
,则它将像常规唯一索引一样工作,并将阻止添加第二行。如果有两个具有相同
client
和option
的数据列,而且这两个数据列都具有custom_id IS NULL
,则索引会防止加入第二个数据列,因为它会索引-42
而非NULL
,而且这两个索引Tuple会相同。mrfwxfqh3#
有没有一种方法可以使null被视为一个值?
从Postgres 15开始,有一种方法是增加了子句**
NULLS NOT DISTINCT
**。你的索引现在可以是:字符集
注意:
null
在同一索引的所有索引列中被视为一个值(与另一个null
冲突),而不仅仅是在option
中。但这无论如何都是无效的,而custom
和client
被定义为NOT NULL
。详细信息:
xlpyo6sf4#
我为
NULLS NOT DISTINCT
创建了一个自定义编译器参数字符集
请注意,Alembic处理得很好。