在 Postgres 上使用 sqlalchemy 创建部分唯一索引
Posted
技术标签:
【中文标题】在 Postgres 上使用 sqlalchemy 创建部分唯一索引【英文标题】:Creating partial unique index with sqlalchemy on Postgres 【发布时间】:2015-03-14 15:04:51 【问题描述】:SQLAlchemy 支持创建partial indexes in postgresql。
是否可以通过 SQLAlchemy 创建partial unique index?
想象一个表格/模型:
class ScheduledPayment(Base):
invoice_id = Column(Integer)
is_canceled = Column(Boolean, default=False)
我想要一个唯一的索引,其中对于给定的发票只能有一个“有效”的 ScheduledPayment。
我可以在 postgres 中手动创建:
CREATE UNIQUE INDEX only_one_active_invoice on scheduled_payment
(invoice_id, is_canceled) where not is_canceled;
我想知道如何使用 SQLAlchemy 0.9 将其添加到我的 SQLAlchemy 模型中。
【问题讨论】:
【参考方案1】:class ScheduledPayment(Base):
id = Column(Integer, primary_key=True)
invoice_id = Column(Integer)
is_canceled = Column(Boolean, default=False)
__table_args__ = (
Index('only_one_active_invoice', invoice_id, is_canceled,
unique=True,
postgresql_where=(~is_canceled)),
)
【讨论】:
这个问题是对我自己的健全性检查。是否可以在不将is_canceled
作为索引定义的一部分的情况下定义索引。来自postgres docs about partial indexes:“强制满足索引谓词的行之间的唯一性,而不限制那些不满足的行”。所以,Index('only_one_active_invoice', invoice_id, unique=True, postgresql_where=~is_canceled)
在定义中只使用invoice_id
就足够了,因为我们只想考虑未取消的发票,对吧?【参考方案2】:
如果有人停下来寻找使用可以选择为NULL
的列设置部分唯一约束,方法如下:
__table_args__ = (
db.Index(
'uk_providers_name_category',
'name', 'category',
unique=True,
postgresql_where=(user_id.is_(None))),
db.Index(
'uk_providers_name_category_user_id',
'name', 'category', 'user_id',
unique=True,
postgresql_where=(user_id.isnot(None))),
)
其中user_id
是一个可以是NULL
的列,我希望在(name, category, user_id)
的所有三个列中强制执行唯一约束,而NULL
只是user_id
的允许值之一。
【讨论】:
【参考方案3】:为了补充 sas 的答案,postgresql_where 似乎无法接受多个布尔值。因此,在您有两个可空列的情况下(让我们假设一个额外的“价格”列),不可能为 NULL/~NULL 的所有组合设置四个部分索引。
一种解决方法是使用永远不会“有效”的默认值(例如,-1 表示价格或“”表示文本列。它们可以正确比较,因此最多允许一行具有这些默认值.
显然,您还需要在所有现有数据行中插入此默认值(如果适用)。
【讨论】:
以上是关于在 Postgres 上使用 sqlalchemy 创建部分唯一索引的主要内容,如果未能解决你的问题,请参考以下文章
在 Postgres/SQLAlchemy 上设置 application_name
如何使用 Postgres 在 SQLAlchemy 中创建表?
使用 sqlalchemy 将 onupdate="cascade" 添加到 postgres 中的现有列
在 postgres 中使用 sqlalchemy 访问复合数据类型