用于向列组合添加唯一约束的迁移

ran*_*alo 132 database ruby-on-rails

我需要的是迁移以将唯一约束应用于列的组合.即对于一个people表,一个组合first_name,last_Name并且Dob应该是唯一的.

Rob*_*her 233

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

  • 模型级验证的问题在于它不能扩展.两个服务器可以同时运行相同的数据(就像在api繁重的应用程序上双击一样)我现在在我的数据库中有两个相同的记录,模型有验证. (17认同)
  • 不,这一切都很好.我的错!唯一约束带有唯一索引. (16认同)
  • 我认为这是一个独特的索引,*不是一个约束.或者索引是否也添加约束? (12认同)
  • 我同意@ paul-cantrell:没有任何方法只添加约束,而不是索引(具有数据库存储影响) (7认同)
  • 我喜欢这两个..只是为了确保 (6认同)
  • @ baash05我在这里因为这个确实存在问题,两台服务器同时运行相同的数据,由我的API请求.在这种情况下,模型验证是无用的 (2认同)

A F*_*kly 23

根据howmanyofme.com,"仅在美国就有46,427人名叫约翰史密斯".那是大约127年的日子.由于这远远超过了人类的平均寿命,这意味着DOB冲突在数学上是确定的.

我只是说,独特领域的特殊组合可能会导致未来极端的用户/客户挫败感.

如果合适的话,考虑一些实际上独特的东西,如国家识别号码.

(我意识到我参加派对的时间已经很晚了,但它可以帮助未来的读者.)

  • hrm ......你当然是对的.但这可能只是伊恩想要做的一个例子,只是为了让问题清楚. (2认同)
  • 也许。不过,这个答案并不是针对 Ian 的。或者确实是Rangalo。 (2认同)

Jos*_*osh 19

您可能希望添加没有索引的约束.这取决于您使用的数据库.以下是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
Run Code Online (Sandbox Code Playgroud)

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

  • [Docgre for PostgreSQL 9.4](http://www.postgresql.org/docs/9.4/static/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS)说:_添加一个唯一约束将自动创建一个唯一的btree索引在约束中使用的列或列组.只有某些行的唯一性约束可以通过创建部分索引来强制执行.所以恕我直言,当结果与使用`add_index`方法基本相同时,不需要删除原始SQL.;) (12认同)
  • 实际上有一个原因:它是一个实现细节,并且被[docs](http://www.postgresql.org/docs/9.3/static/indexes-unique.html)所劝阻.另请注意,您不能通过名称引用约束,因为它未添加到`pg_constraint`表中. (8认同)

Kha*_*oui 12

为了完整起见,并避免混淆,这里有 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
Run Code Online (Sandbox Code Playgroud)

或者这个块版本。

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
Run Code Online (Sandbox Code Playgroud)

或者这个原始 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
Run Code Online (Sandbox Code Playgroud)

其中任何一个都会有相同的结果,请检查您的 schema.rb


Boh*_*dan 7

嗨您可以在迁移到列时添加唯一索引

add_index(:accounts, [:branch_id, :party_id], :unique => true)
Run Code Online (Sandbox Code Playgroud)

或为每列分隔唯一索引


Dor*_*ian 5

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

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
Run Code Online (Sandbox Code Playgroud)

尝试创建两个相似的记录将引发数据库错误(在我的情况下为 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"
Run Code Online (Sandbox Code Playgroud)

例如这样做:

Ownership.create!(user_id: user_id, post_id: post_id)
Ownership.create!(user_id: user_id, post_id: post_id)
Run Code Online (Sandbox Code Playgroud)

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

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