在 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 访问复合数据类型

如何使用Flask,SQLAlchemy或psycopg2从Postgres中的光标获取数据

我从 sqlalchemy 得到一个“幽灵”回滚,但在使用 psql 和 postgres 时没有