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

sto*_*one 1 mysql sql

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

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

  1. 列X带有A,列Y带有B.
  2. 列X带有B,列Y带有A.

我会给出一个场景

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

我有一个独特的约束添加到tbl_challenger as

UNIQUE KEY `UNIQUE_PARTICIPANTS` (`host`,`challenger`)
Run Code Online (Sandbox Code Playgroud)

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

INSERT INTO `tbl_challenger` VALUES(678498 , 679879); 
Run Code Online (Sandbox Code Playgroud)

但是,遗憾的是,如果同时userB尝试与用户A发起游戏,我们就会得到

INSERT INTO `tbl_challenger` VALUES(679879, 678498 ); 
Run Code Online (Sandbox Code Playgroud)

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

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

Mic*_*ker 8

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

CREATE TABLE tbl_challenger (
  host int,
  challenger int,
  u0 int, u1 int
);
Run Code Online (Sandbox Code Playgroud)

并添加一些设置的触发器,u0以及u1两者中最小和最大的触发器:

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);
Run Code Online (Sandbox Code Playgroud)

然后你添加一个唯一的索引 (u0,u1)

CREATE UNIQUE INDEX uniqueness ON tbl_challenger(u0,u1);
Run Code Online (Sandbox Code Playgroud)

现在,无论顺序如何,您都会在尝试插入重复对时遇到错误.

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

CREATE UNIQUE INDEX uniqueness ON tbl_challenger
    ( LEAST(host,challenger), GREATEST( host,challenger) );
Run Code Online (Sandbox Code Playgroud)

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