【问题标题】:Unicity on two columns asymmetrically两列不对称的唯一性
【发布时间】:2016-09-03 23:18:21
【问题描述】:
这是我的桌子Friendship(user_id1:integer, user_id2:integer)
我想在数据库中添加一个约束,这样如果几个 user_id 的对称性已经存在,就会被拒绝。
例如,如果我在数据库中已经有(42, 17) 这对夫妇,我不希望能够保存(17, 42)
我正在使用带有 postgresql 的 Rails。
【问题讨论】:
标签:
ruby-on-rails
postgresql
constraints
unique-constraint
【解决方案1】:
您可以使用表达式索引在数据库中执行此操作:
create unique index unq_friendship_1_2
on (least(user_id1, user_id2), greatest(user_id1, user_id2));
我不知道你在 Rails 中是如何表达的。
【解决方案2】:
如果您能够以某种方式实现应用程序,您可以结合使用普通唯一约束和检查约束来执行此操作,它将较小的值存储在字段 user_id_1 中,将较大的值存储在字段 user_id_2 中.
在 (user_id_1, user_id_2) 上定义一个唯一约束,另外定义一个检查约束,即 (user_id_1
在 Oracle 中是
ALTER TABLE tablename ADD CONSTRAINT cname1 UNIQUE (user_id_1, user_id_2)
ALTER TABLE tablename ADD CONSTRAINT cname2 CHECK (user_id_1 <= user_id_2)
如果您的应用程序无法插入如上所述排序的值,您仍然可以使用例如触发器,但这是更特定于 DB 供应商的。
【解决方案3】:
您可以在 Rails 中这样做。
在您的 Rails 模型 friendship.rb 中,添加以下 validates_uniqueness 调用:
validates_uniqueness_of :user_id1, :scope => :user_id2。
这保证不会有两个相同的user_id1s 或user_id2s 对。
但是,@potashin 解释说这种方法并不完全安全,因为如果同时发送了两个请求,它们可能会被接受,并且您的行会重复。他的解决方案是将以下迁移添加到您的 Friendships 模型中:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :friendships, [:user_id1, :user_id2], unique: true
end
end