5

如何有效地在表中的两个字段上创建唯一索引,如下所示: create table t (a integer, b integer);

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

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

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

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

4

4 回答 4

6

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

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

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 的响应中)或在应用程序中更高层处理。

于 2008-10-23T13:56:26.527 回答
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;
于 2008-10-23T12:21:44.923 回答
2

在 Oracle 中,您可以使用这样的基于函数的索引:

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

我不知道 mySQL,但也许类似的东西是可能的?例如,您可以向表中添加 2 个新列 minimumab 和 greatab ,最大)。

于 2008-10-23T12:23:00.613 回答
1

请参阅两个外键而不是主键

于 2008-10-23T11:53:20.643 回答