【发布时间】:2011-03-23 03:59:50
【问题描述】:
我需要迁移以将唯一约束应用于列组合。即对于people 表,first_name、last_Name 和 Dob 的组合应该是唯一的。
【问题讨论】:
-
仅供阅读此问题的任何人参考:不要根据名字、姓氏和出生日期进行限制,因为这三个都可以匹配多个人。 (这在答案中提到,但它不是真正的答案。)
我需要迁移以将唯一约束应用于列组合。即对于people 表,first_name、last_Name 和 Dob 的组合应该是唯一的。
【问题讨论】:
add_index :people, [:firstname, :lastname, :dob], :unique => true
【讨论】:
您可能想要添加不带索引的约束。这取决于您使用的数据库。下面是 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
您可以添加不同的约束。 Read the docs
【讨论】:
add_index 方法基本相同时,无需使用原始 SQL。 ;)
pg_constraint 表中。
根据 howmanyofme.com 的数据,仅在美国,“就有 46,427 人叫 John Smith”。那是大约127年的日子。由于这远远超过了人类的平均寿命,这意味着 DOB 冲突在数学上是确定的。
我想说的是,独特字段的特定组合可能会在未来导致用户/客户极度沮丧。
考虑一些真正独特的东西,比如国家身份证号码,如果合适的话。
(我意识到我参加这个聚会很晚了,但它可以帮助未来的读者。)
【讨论】:
为了完整起见,为了避免混淆,这里有 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
【讨论】:
您好,您可以在迁移中为列添加唯一索引,例如
add_index(:accounts, [:branch_id, :party_id], :unique => true)
或为每列单独的唯一索引
【讨论】:
在用户和帖子之间的连接表的典型示例中:
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
【讨论】: