两列不对称的单一性

时间:2016-05-09 10:45:54

标签: ruby-on-rails postgresql constraints unique-constraint

这是我的表Friendship(user_id1:integer, user_id2:integer)

我想在数据库中添加一个约束,这样如果它的symetric已经存在,那么将拒绝几个user_id。

例如,如果我已经在数据库中拥有这对夫妇(42, 17),我就不希望能够保存(17, 42)

我在postgresql中使用rails。

3 个答案:

答案 0 :(得分:0)

您可以使用表达式索引在数据库中执行此操作:

create unique index unq_friendship_1_2
     on (least(user_id1, user_id2), greatest(user_id1, user_id2));

我不知道你是如何在rails中表达的。

答案 1 :(得分:0)

如果您能够以某种方式实现应用程序,它可以在字段user_id_1中存储较小的值,而在字段user_id_2中存储较大的值,则可以使用常规唯一约束和检查约束的组合来执行此操作

在(user_id_1,user_id_2)上定义一个唯一约束,另外还有一个检查约束(user_id_1< = user_id_2),以验证您的应用程序是否按照上面定义的方式运行。

在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)

如果您的应用程序无法插入按上述方式排序的值,您仍然可以使用例如触发器,但这是更具有数据库供应商特定的。

答案 2 :(得分:0)

您可以在Rails中这样做。 在您的Rails模型friendship.rb中,添加以下validates_uniqueness调用:

validates_uniqueness_of :user_id1, :scope => :user_id2。 这样可以保证不会有user_id1user_id2的两个相同的对。

但是,@potashin解释说这种方法并不完全安全,因为如果同时发送两个请求,它们可能会被接受并且您的行将被复制。他的解决方案是还将以下迁移添加到您的Friendships模型中:

class AddUniqueConstraints < ActiveRecord::Migration
  def change
   add_index :friendships, [:user_id1, :user_id2], unique: true
  end
end