【问题标题】:How To Create A 'Two-Sided' Unique Index On Two Fields?如何在两个字段上创建“双面”唯一索引?
【发布时间】:2008-10-23 11:49:52
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: mysql database-design indexing constraints unique


    【解决方案1】:

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

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

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

    【讨论】:

    • 您的第一个答案非常适合我。谢谢。我希望有一个更“自然”的解决方案,但我想就是这样。
    【解决方案2】:

    我认为这只能使用 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;
    

    【讨论】:

    • 已在 MySQL 下修复和测试。如果有人知道是否可以直接从触发器中引发错误以停止插入,那会很方便......
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 这不涉及“以任何顺序”的要求
      猜你喜欢
      • 2020-05-16
      • 2022-01-04
      • 2010-09-16
      • 1970-01-01
      • 2015-03-01
      • 2013-06-22
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      相关资源
      最近更新 更多