迁移以向列组合添加唯一约束


140

我需要的是将唯一约束应用于列组合的迁移。即对于people表的组合first_namelast_NameDob应该是唯一的。

Answers:


242

add_index :people, [:firstname, :lastname, :dob], :unique => true


12
我认为这是在添加唯一索引,而不是约束。还是索引也添加了约束?
Paul Cantrell

16
不,一切都很好。我的错!唯一约束带有唯一索引。
保罗·坎特雷尔

7
我同意@ paul-cantrell:没有什么方法只能添加约束,而不是添加索引(具有数据库存储影响)
Augustin Riedinger 2013年

17
模型级别验证的问题在于它无法扩展。两台服务器可以同时运行相同的数据(例如在api大量应用程序上双击),我的数据库中现在有两条相同的记录,并且该模型已经过验证
。–

6
我想同时拥有两者。.为了确保
baash05 2015年

25

根据howmanyofme.com的统计,仅在美国,就有46,427人被命名为John Smith。那大约是127年的日子。由于这已经超过了人类的平均寿命,因此这意味着DOB冲突在数学上是确定的。

我要说的是,独特字段的特定组合将来可能会导致极大的用户/客户挫败感。

如果合适,考虑一下实际上是唯一的东西,例如国家识别号。

(我意识到我参加这一晚会很晚,但是它可以帮助将来的读者。)


3
嗯...你当然是对的。但这可能只是Ian想要做的一个例子,目的只是为了使问题更明确。
eritiro '16

1
也许。答案并不是给伊恩的。甚至确实是兰加洛。
黑暗的推子

它适用于所有foo-s,而不仅仅是Ian或rangalo。
ARK

20

您可能要添加没有索引的约束。这将取决于您使用的数据库。以下是Postgres的示例迁移代码。 (tracking_number, carrier)是要用于约束的列的列表。

class AddUniqeConstraintToShipments < ActiveRecord::Migration
  def up
    execute <<-SQL
      alter table shipments
        add constraint shipment_tracking_number unique (tracking_number, carrier);
    SQL
  end

  def down
    execute <<-SQL
      alter table shipments
        drop constraint if exists shipment_tracking_number;
    SQL
  end
end

您可以添加不同的约束。 阅读文档


12
PostgreSQL 9.4的文档说:添加唯一约束将在约束中使用的列或一组列上自动创建唯一的btree索引。通过创建部分索引,可以对仅某些行执行唯一性约束。 因此,恕我直言,当结果与使用该add_index方法基本相同时,无需删除原始SQL 。;)
RafałCieślak2015年

8
实际上,有一个原因:这是一个实现细节,但docs不建议这样做。还要注意,您不能按名称引用约束,因为它没有添加到pg_constraint表中。
kaikuchn 2015年

8

您好,例如,您可以在迁移中向列添加唯一索引

add_index(:accounts, [:branch_id, :party_id], :unique => true)

或为每列单独的唯一索引


抱歉,它起作用了,首先我尝试通过编辑和现有的迁移来解决问题,然后再添加一个新的,它就可以了,谢谢。
rangalo 2010年

4

在用户和帖子之间的联接表的典型示例中:

create_table :users
create_table :posts

create_table :ownerships do |t|
  t.belongs_to :user, foreign_key: true, null: false
  t.belongs_to :post, foreign_key: true, null: false
end

add_index :ownerships, [:user_id, :post_id], unique: true

尝试创建两个相似的记录将引发数据库错误(在我的情况下为Postgres):

ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_ownerships_on_user_id_and_post_id"
DETAIL:  Key (user_id, post_id)=(1, 1) already exists.
: INSERT INTO "ownerships" ("user_id", "post_id") VALUES ($1, $2) RETURNING "id"

例如这样做:

Ownership.create!(user_id: user_id, post_id: post_id)
Ownership.create!(user_id: user_id, post_id: post_id)

完全可运行的示例:https : //gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

db/schema.rb生成:https : //gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a


4

为了完整起见,并避免混淆,这里有3种方法来做同一件事:
在Rails 5.2+中将命名的唯一约束添加到列的组合中

假设我们有一个属于广告客户的Locations表,并且具有reference_code列,而每个广告客户只需要1个参考代码。因此您想向列组合添加唯一约束并命名。

做:

rails g migration AddUniquenessConstraintToLocations

并使您的迁移看起来像这样的一种衬板:

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    add_index :locations, [:reference_code, :advertiser_id], unique: true, name: 'uniq_reference_code_per_advertiser'
  end
end

或此块版本。

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    change_table :locations do |t|
     t.index ['reference_code', 'advertiser_id'], name: 'uniq_reference_code_per_advertiser', unique: true
    end
  end
end

或此原始SQL版本

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
      execute <<-SQL
          ALTER TABLE locations
            ADD CONSTRAINT uniq_reference_code_per_advertiser UNIQUE (reference_code, advertiser_id);
        SQL
  end
end

这些结果都会相同,请检查您的 schema.rb

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.