How To Create A 'Two-Sided' Unique Index On Two Fields?

廉价感情. 提交于 2019-11-28 13:46:19

How about controlling what goes into the table so that you always store the smallest number into the first column and the largest one in the second? As long as it 'means' the same thing of course. It's probably less expensive to do it before it even gets to the database.

If this is impossible, you could save the fields as is but have them duplicated in numerical order into two OTHER fields, on which you would create the primary key (pseudo code-ish) :

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 )

This could easily be done with a trigger (as in Ronald's response) or handled higher up, in the application.

I think this can only be done using a FOR INSERT trigger (in combination with a unique constraint on the two columns). I'm not really fluent in MySql syntax (my T-SQL is better), so I guess the following will contain some errors:

Edit: Cleaned up the syntax so it works for MySQL. Also, note you'll probably want to put this as a BEFORE UPDATE trigger too (with a different name of course).

Also, this method relies on having a primary or otherwise unique key on the two fields (ie. this trigger only checks the reverse doesn't already exist.) There doesn't seem to be any way of throwing an error from a trigger, so I dare say this is as good as it gets.

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;

In Oracle you could use a function-based index like this:

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

I don't know mySQL, but maybe something similar is possible? For example, you could add 2 new columns leastab and greatestab to the table, with a trigger to maintain them with the values of least(a,b) and greatest(a,b) respectively, and then create a unique index on (leastab, greatestab).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!