如何跨多个列实现双向唯一索引

时间:2009-09-20 12:03:27

标签: sql mysql

好的,我知道我可以在应用程序层执行此操作,这可能是最简单的事情,但只是为了确保没有错误流入数据库,我有一个严肃的问题

我有两列X和Y,每列都存储两个整数(任何一列中的A或B)。是否有可能有一个唯一的索引约束,在任何情况下我们都不应该

  1. 列X带有A,列Y带有B
  2. X列为B,Y列为A
  3. 我会给出一个场景

    我有两个用户,userA的ID为678498,userB的ID为679879.两个用户都要玩2人游戏,这需要将此会话的新记录存储在表(tbl_chalenger)中。为此,我有一个包含“host”和“challenger”列的表。

    我有一个独特的约束作为

    添加到tbl_challenger
    UNIQUE KEY `UNIQUE_PARTICIPANTS` (`host`,`challenger`)
    

    品牌用户主机或挑战者基本上取决于谁发起了游戏。因此,如果userA启动游戏,我们会进行如下查询

    INSERT INTO `tbl_challenger` VALUES(678498 , 679879); 
    

    创建一个新记录,遗憾的是,如果同时userB尝试与用户A发起游戏,我们得到

    INSERT INTO `tbl_challenger` VALUES(679879, 678498 ); 
    

    这会创建相同参与者的新不需要的行。这与UNIQUE键约束无关。

    所以我的问题是如何设置双向约束?这样“主机挑战者”和“挑战者主机”不能拥有相同的数据对

2 个答案:

答案 0 :(得分:8)

在mysql中,我能想到的唯一方法是添加几个实用程序列,如

CREATE TABLE tbl_challenger (
  host int,
  challenger int,
  u0 int, u1 int
);

并添加一些触发器,将u0u1设置为最小和最大的两个:

CREATE TRIGGER uinsert BEFORE INSERT ON tbl_challenger
 FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger),
  NEW.u1 = GREATEST(NEW.host,NEW.challenger);
CREATE TRIGGER uupdate BEFORE UPDATE ON tbl_challenger
 FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger),
  NEW.u1 = GREATEST(NEW.host,NEW.challenger);

然后在(u0,u1)

上添加唯一索引
CREATE UNIQUE INDEX uniqueness ON tbl_challenger(u0,u1);

现在无论订单如何,您都会在尝试插入重复对时遇到错误。

在像PostgreSQL这样体面的RDBMS上,你可以在表达式上使用索引:

CREATE UNIQUE INDEX uniqueness ON tbl_challenger
    ( LEAST(host,challenger), GREATEST( host,challenger) );

所以,在为时已晚之前切换; - )

答案 1 :(得分:1)

我认为你不能“开箱即用”,比如使用UNIQUE索引或类似的东西。

但是,您可能可以使用触发器实现这种检查,在插入和更新之前触发。

我已经很长时间没有使用触发器,而且它不在MySQL上,所以我无法给你任何例子,但是这里是手册的相关页面:12.1.19. CREATE TRIGGER Syntax < / p>

作为旁注:正如您所说,这种约束通常在应用程序端实现。