如何在两个字段上创建“双面”唯一索引?

时间:2008-10-23 11:49:53

标签: mysql database-design indexing constraints unique

如何在表格中的两个字段上高效创建唯一索引,如下所示: create table t(一个整数,b整数);

其中两个不同数字的任何唯一组合在表格的同一行上不能出现多次。

如果存在一行,使得a = 1且b = 2,则在a = 2和b = 1或a = 1且b = 2的情况下,不存在另一行。换句话说,两个数字不能以任何顺序一起出现多次。

我不知道这样的约束是什么,因此标题中的“双面唯一索引”名称。

更新:如果我在列(a,b)上有复合键,并且数据库中存在行(1,2),则可以插入另一行(2,1) )没有错误。我正在寻找的方法是防止同一对数字以任何顺序多次使用 ......

4 个答案:

答案 0 :(得分:6)

如何控制进入表中的内容,以便始终将最小的数字存储到第一列中,将最大的数字存储在第二列中?只要它“意味着”同样的事情当然。在它进入数据库之前,它可能更便宜。

如果这是不可能的,你可以保存字段,但是按照数字顺序将它们复制到两个OTHER字段中,你将在其上创建主键(伪代码):

COLUMN A : 2
COLUMN B : 1

COLUMN A_PK : 1  ( if new.a < new.b then new.a else new.b )
COLUMN B_PK : 2  ( if new.b > new.a then new.b else new.a )

这可以通过触发器(如Ronald的回复中)轻松完成,也可以在应用程序中处理得更高。

答案 1 :(得分:3)

我认为这只能使用FOR INSERT触发器(结合两列上的唯一约束)来完成。我不是真的流利的MySql语法(我的T-SQL更好),所以我猜以下将包含一些错误:

编辑:清除语法,使其适用于MySQL。另外,请注意,您可能也希望将其作为BEFORE UPDATE触发器(当然使用其他名称)。

此外,此方法依赖于在两个字段上具有主键或其他唯一键(即,此触发器仅检查反向还不存在。)似乎没有任何方法可以抛出错误一个触发器,所以我敢说这是最好的。

CREATE TRIGGER tr_CheckDuplicates_insert
BEFORE INSERT ON t
FOR EACH ROW
BEGIN
    DECLARE rowCount INT;
    SELECT COUNT(*) INTO rowCount
                   FROM t
                   WHERE a = NEW.b AND b = NEW.a;

    IF rowCount > 0 THEN
        -- Oops, we need a temporary variable here. Oh well.
        -- Switch the values so that the key will cause the insert to fail.
        SET rowCount = NEW.a, NEW.a = NEW.b, NEW.b = rowCount;
    END IF;
END;

答案 2 :(得分:2)

在Oracle中,您可以使用基于函数的索引,如下所示:

create unique index mytab_idx on mytab (least(a,b), greatest(a,b));

我不知道mySQL,但也许类似的东西可能吗?例如,您可以向表中添加2个新列leastab和maximumab,并使用触发器分别使用最小值(a,b)和最大值(a,b)维护它们,然后在(leastab)上创建唯一索引,greatab)。

答案 3 :(得分:1)