web-dev-qa-db-ja.com

Postgresでsqlalchemyを使用して部分的に一意のインデックスを作成する

SQLAlchemyは作成をサポートします postgresqlの部分インデックス

SQLAlchemyを介して partialuniqueindex を作成することは可能ですか?

テーブル/モデルを次のように想像してください。

class ScheduledPayment(Base):
     invoice_id = Column(Integer)
     is_canceled = Column(Boolean, default=False)

特定の請求書に対して「アクティブな」ScheduledPaymentが1つだけ存在できる一意のインデックスが必要です。

私はこれをpostgresで手動で作成できます:

CREATE UNIQUE INDEX only_one_active_invoice on scheduled_payment 
     (invoice_id, is_canceled) where not is_canceled;

SQLAlchemy0.9を使用してSQLAlchemyモデルにそれを追加するにはどうすればよいのでしょうか。

27
brianz
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)),
    )
32
van

オプションで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_idNULLにすることができる列であり、NULL(name, category, user_id)の許可値の1つであるuser_idの3つの列すべてに一意の制約を適用したい。

6
sas

Sasによる回答に追加するために、postgresql_whereは複数のブール値を受け入れることができないようです。したがって、NULL可能な列が2つある状況(追加の「価格」列を想定します)では、NULL/〜NULLのすべての組み合わせに対して4つの部分インデックスを持つことはできません。

回避策の1つは、「有効」になることのないデフォルト値を使用することです(たとえば、価格の場合は-1、テキスト列の場合は ''。これらは正しく比較されるため、これらのデフォルト値を持つことができるのは1行のみです。

もちろん、このデフォルト値を既存のすべてのデータ行に挿入する必要もあります(該当する場合)。

0
Ng Oon-Ee