![](/img/trans.png)
[英]IntegrityError: distinguish between unique constraint and not null violations
[英]Treating `null` as a distinct value in a table unique constraint
我有一个表,用于为客户端定义默认和自定义选项。 如果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 |
+----+----------+----------+--------+---------------------------------------------+
这个相关的答案是我正在寻找的,使用 MySQL。 理想的解决方案是使用 sqlalchemy 来做到这一点。
我会做
CREATE UNIQUE INDEX ON atable
(client, option, coalesce(custom_id, -42));
其中-42
是custom_id
不能出现的值。
它是如何工作的?
如果有两行具有相同的client
、 option
和custom_id
,所有这些都不是NOT NULL
,它将像常规唯一索引一样工作,并阻止添加第二行。
如果有两行具有相同client
和option
行都具有custom_id IS NULL
,则索引将阻止添加第二行,因为它索引-42
而不是NULL
,并且两个索引元组将相同。
将 sqlalchemy 用于问题中的示例,如下所示:
class OptionTable(Base):
__tablename__ = "option_table"
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)
__table_args__ = (
Index(
"uix_custom_client_option",
"custom_id",
"client",
"option",
unique=True,
postgresql_where=custom_id.isnot(None)
),
Index(
"uix_client_option",
"client",
"option",
unique=True,
postgresql_where=custom_id.is_(None)
),
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.