【问题标题】:Table constraint for data pair regardless of order无论顺序如何,数据对的表约束
【发布时间】:2015-11-20 20:15:53
【问题描述】:

我有两张桌子;朋友和用户。

用户表,略微简化:

CREATE TABLE users (
    id bigserial NOT NULL,
    fname text,
    lname text,
    username text,
    created timestamp without time zone DEFAULT now(),
    CONSTRAINT users_pkey PRIMARY KEY (id)
)

Friends 表是一个连接表

CREATE TABLE friends
(
    user_id bigint,
    friend_id bigint,
    accepted boolean DEFAULT false
)

所以朋友表只是将一个用户映射到另一个用户,所以用户 1 可以与用户 2 成为朋友。

我的问题:如何约束表格,使两对 (1, 2) , (2,1) 不会插入表格中?

我知道我可以使用unique (user_id , friend_id) 来防止插入像 (1,2) 这样的重复行...

但是如果 (1, 2) 已经存在,如何防止插入 (2, 1)?

【问题讨论】:

标签: sql postgresql


【解决方案1】:

在表达式上使用索引:

create unique index unq_friends_user_friend
    on (least(user_id, friend_id), greatest(user_id, friend_id));

编辑:

由于其他答案,我需要详细说明。

请注意,这种方法涉及数据库中的一行代码(好吧,我承认我在答案中将其分为两行;)

尝试在应用层复制此代码需要:

  • 用于检查任一对是否存在的复杂查询。
  • 我应该指出,这个复杂的查询很难优化(尤其是在答案中)。
  • 在任何insert 之前运行查询并检查结果的应用程序代码。
  • 哦,updates 也是如此。嗯,留给读者作为练习如何处理更新,尤其是多行更新。

在经历了所有这些麻烦之后,你仍然遇到了比赛条件的问题。两个线程可能会尝试插入相同的两个朋友。两者都没有看到冲突。两者都做插入。现在,您有重复项。

这使得单线解决方案真的很容易。

【讨论】:

  • 糟糕的计划:使用约束而不是索引来强制约束。恕我直言。
  • 唯一约束和唯一索引本质上做同样的事情(唯一索引用于实现唯一约束)。唯一约束的一个小优点是大多数数据库在报告错误时都会使用约束的名称。
猜你喜欢
  • 2012-07-10
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多