2008-10-23 35 views
5

Wie kann ich effizient einen eindeutigen Index für zwei Felder in einer Tabelle wie folgt erstellen: create table t (eine ganze Zahl, b ganze Zahl);Wie erstellt man einen 'zweiseitigen' eindeutigen Index auf zwei Feldern?

wobei eine eindeutige Kombination zweier verschiedener Zahlen nicht mehr als einmal in derselben Zeile in der Tabelle vorkommen darf.

In Wörtern, wenn eine Zeile existiert, so dass a = 1 und b = 2, kann eine andere Zeile nicht existieren, wo a = 2 und b = 1 oder a = 1 und b = 2. Mit anderen Worten, zwei Zahlen können nicht mehr als einmal in beliebiger Reihenfolge zusammen auftreten.

Ich habe keine Ahnung, wie eine solche Einschränkung aufgerufen wird, daher der Name "doppelseitigen eindeutigen Index" im Titel.

Update: Wenn ich einen zusammengesetzten Schlüssel auf Spalten (a, b) und eine Zeile (1,2) in der Datenbank existiert, ist es möglich, eine andere Zeile (2,1) ohne Fehler einzufügen . Was ich suche ist eine Möglichkeit, das gleiche Paar von Zahlen zu verhindern, dass mehr genutzt als einmal in beliebiger Reihenfolge ...

Antwort

5

Wie wäre es, zu kontrollieren, was in die Tabelle passt, so dass Sie immer die kleinste Zahl in der ersten Spalte und die größte in der zweiten Spalte speichern? Solange es natürlich "dasselbe" bedeutet. Es ist wahrscheinlich billiger, es zu tun, bevor es überhaupt in die Datenbank kommt.

Wenn dies nicht möglich ist, können Sie die Felder speichern wie sie aber in numerischer Reihenfolge in zwei anderen Bereichen dupliziert haben, auf dem Sie den Primärschlüssel (Pseudo-Code-ish) erzeugen würde:

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) 

Dies könnte leicht mit einem Trigger (wie in Ronalds Antwort) oder höher behandelt werden, in der Anwendung.

+0

Ihre erste Antwort ist perfekt für mich. Vielen Dank. Ich hatte gehofft, es wäre eine "natürlichere" Lösung, aber ich denke, das ist es. –

3

Siehe ich denke, das nur getan werden kann, mit a FOR INSERT-Trigger (in Kombination mit einer eindeutigen Einschränkung für die beiden Spalten). Ich bin nicht wirklich fließend in MySql-Syntax (meine T-SQL ist besser), so dass das Folgende wird einige Fehler enthalten:

Edit: Die Syntax aufgeräumt, so dass es für MySQL funktioniert. Beachten Sie auch, dass Sie dies wahrscheinlich auch als BEFORE UPDATE Trigger (mit einem anderen Namen natürlich) setzen möchten.

Auch diese Methode beruht auf einem primären oder anderweitig eindeutigen Schlüssel auf den beiden Feldern (dh. Dieser Trigger prüft nur, dass die Umkehrung noch nicht existiert.) Es scheint keinen Weg zu geben, einen Fehler zu werfen von einem Auslöser, also wage ich zu sagen, das ist so gut wie es geht.

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

Ich weiß nicht, mySQL, aber vielleicht etwas Ähnliches ist möglich:

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; 
+0

unter MySQL behoben und getestet.Wenn jemand weiß, ob es möglich ist, einen Fehler direkt von einem Auslöser zu werfen, um den Einsatz zu stoppen, wäre das praktisch zu wissen ... –

2

In Oracle können Sie einen funktionsbasierten Index wie folgt verwenden? Beispielsweise könnten Sie der Tabelle zwei neue Spalten hinzufügen, lestab und greatab, mit einem Auslöser, um sie mit den Werten von mindestens (a, b) bzw. größten (a, b) zu verwalten und dann einen eindeutigen Index für (lastab , am bestenab).

Verwandte Themen