Frage

Erstellen einer Tabelle mit Composite PRIMARY KEY oder verwenden UNIQUE INDEX Für zwei Spalten garantieren Col1 die Einzigartigkeit von COL1. Gibt es einen schwierigen Ansatz, um die umgekehrte Reihenfolge zweier Spalten auch einzigartig zu machen (Col2, Col1)?

Zum Beispiel

PRIMARY KEY (col1, col2)

ODER

UNIQUE INDEX (col1, col2)

Wenn wir haben col1=33 && col2=54; Wie wir vermeiden können INSERT von col1=54 && col2=33?

War es hilfreich?

Lösung

Möglicherweise möchten Sie versuchen, einen Auslöser zu erstellen, der auf das Vorhandensein von (col1, col2) as (col2, col1) prüft (col1, col2).

Hier ist ein Beispiel:

use test
drop table if exists ali;
create table ali
(
    col1 int not null,
    col2 int not null,
    primary key (col1,col2)
);
DELIMITER $$
CREATE TRIGGER ali_bi BEFORE INSERT ON ali FOR EACH ROW 
BEGIN 
    DECLARE found_count,newcol1,newcol2,dummy INT;
    SET newcol1 = NEW.col1;
    SET newcol2 = NEW.col2;
    SELECT COUNT(1) INTO found_count FROM ali
    WHERE col1 = newcol2 AND col2 = newcol1;
    IF found_count = 1 THEN
        SELECT 1 INTO dummy FROM information_schema.tables;
    END IF;
END; $$ 
DELIMITER ;
INSERT INTO ali VALUES (1,2);
INSERT INTO ali VALUES (3,4);
INSERT INTO ali VALUES (2,1);
INSERT INTO ali VALUES (4,3);
SELECT * FROM ali;

Der Trigger ist so konzipiert, dass er absichtlich brechen kann, wenn found_count 1 ist.

Hier ist das ausgeführte Beispiel:

mysql> use test
Database changed
mysql> drop table if exists ali;
Query OK, 0 rows affected (0.03 sec)

mysql> create table ali
    -> (
    ->     col1 int not null,
    ->     col2 int not null,
    ->     primary key (col1,col2)
    -> );
Query OK, 0 rows affected (0.06 sec)

mysql> DELIMITER $$
mysql> CREATE TRIGGER ali_bi BEFORE INSERT ON ali FOR EACH ROW
    -> BEGIN
    ->     DECLARE found_count,newcol1,newcol2,dummy INT;
    ->     SET newcol1 = NEW.col1;
    ->     SET newcol2 = NEW.col2;
    ->     SELECT COUNT(1) INTO found_count FROM ali
    ->     WHERE col1 = newcol2 AND col2 = newcol1;
    ->     IF found_count = 1 THEN
    ->         SELECT 1 INTO dummy FROM information_schema.tables;
    ->     END IF;
    -> END; $$
Query OK, 0 rows affected (0.07 sec)

mysql> DELIMITER ;
mysql> INSERT INTO ali VALUES (1,2);
Query OK, 1 row affected (0.07 sec)

mysql> INSERT INTO ali VALUES (3,4);
Query OK, 1 row affected (0.06 sec)

mysql> INSERT INTO ali VALUES (2,1);
ERROR 1172 (42000): Result consisted of more than one row
mysql> INSERT INTO ali VALUES (4,3);
ERROR 1172 (42000): Result consisted of more than one row
mysql> SELECT * FROM ali;
+------+------+
| col1 | col2 |
+------+------+
|    1 |    2 |
|    3 |    4 |
+------+------+
2 rows in set (0.00 sec)

mysql>

Versuche es !!!

Vorbehalte Dies funktioniert nicht bei Schüttguteinsätzen. Nur wenn sie jeweils eine Reihe einfügen.

Ich habe diese Technik verwendet und sie in anderen Fragen der DBA -Stackexchange vorgeschlagen

Update 2012-02-29 11:46 EDT

Ich habe versucht, die gleichen vier Zeilen wieder einzufügen.

INSERT INTO ali VALUES (1,2);
INSERT INTO ali VALUES (3,4);
INSERT INTO ali VALUES (2,1);
INSERT INTO ali VALUES (4,3);
SELECT * FROM ali;

Hier ist was ich bekomme

mysql> INSERT INTO ali VALUES (1,2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'PRIMARY'
mysql> INSERT INTO ali VALUES (3,4);
ERROR 1062 (23000): Duplicate entry '3-4' for key 'PRIMARY'
mysql> INSERT INTO ali VALUES (2,1);
ERROR 1172 (42000): Result consisted of more than one row
mysql> INSERT INTO ali VALUES (4,3);
ERROR 1172 (42000): Result consisted of more than one row
mysql> SELECT * FROM ali;
+------+------+
| col1 | col2 |
+------+------+
|    1 |    2 |
|    3 |    4 |
+------+------+
2 rows in set (0.00 sec)

mysql>

Dieser Triggeransatz funktioniert trotz der schrulligen Nachricht gut.

Andere Tipps

In einem Standard -SQL -DBMS würden Sie diese Art von Anforderung durch Bestellung der ID -Nummern und die Verwendung einer Scheckbeschränkung durchsetzen. Anwendungscode, ein gespeicherter Prozedur oder eine benutzerdefinierte Funktion ist für das Einlegen der ID-Nummern in die richtige Reihenfolge verantwortlich.

create table friends (
  user_a integer not null,  -- references users, not shown
  user_b integer not null,  -- references users, not shown
  primary key (user_a, user_b),
  check (user_a < user_b)
);

Aber MySQL erzwingt keine Überprüfungsbeschränkungen. Mit MySQL würde ich weiterhin eine gespeicherte Prozedur (nicht Anwendungscode) verwenden, um die ID -Nummern in die richtige Reihenfolge zu setzen. Aber ich würde auch ab und zu eine Abfrage oder einen Bericht ausführen, um sicherzustellen, dass alle Werte für user_a geringer waren als die Werte für user_b.

select *
from friends
where user_a >= user_b;

Ich würde wahrscheinlich keine Update -Anweisung annehmen, um diese Werte zunächst zu beheben. Ich möchte nachverfolgen, welcher Prozess, die Anwendung oder der Benutzer meine gespeicherte Prozedur umsetzt, um Daten direkt in die Tabelle einzufügen. (Sie können den direkten Zugriff auf die Tabelle widerrufen und alle Zugriff auf gespeicherte Verfahren erfordern. Dies ist jedoch in einigen Legacy -Systemen nicht praktisch. Zu viel Code, um neu zu schreiben. Und es gibt Alternativen.)

Leider müssen einige Anforderungen als Verwaltungsverfahren implementiert werden, z. B. als Ausführen von Berichten.

Diese Regeln können nicht durch einen eindeutigen Index innerhalb von MySQL durchgesetzt werden, selbst wenn Sie einen umgekehrten Index verwenden. Sie müssen diese Regel in Ihrer Anwendungsgeschäftslogik durchsetzen oder einen Datenbankauslöser/-funktion/-verfahren verwenden, der die Daten überprüft, bevor sie gespeichert werden.

Ich weiß, dass das etwas zu spät zum Spiel ist, aber könnte ich hinzufügen ...

Wir haben eine ähnliche Situation, außer dass, wo ID1 und ID2 gleich sind, sie tatsächlich mit derselben Tabelle verknüpfen, die a verbunden Eine Art Funktion, wieder viele zu vielen.

Da wir nach potenziellen IDs suchen würden, die in beiden Spalten möglicherweise vorhanden sind, sind zwei Indizes tatsächlich logischer .... und zweckmäßig ... und nicht sehr kostspielig.

UNIQUE INDEX (col1, col2) + UNIQUE INDEX (col2, col1)

Wenn Sie Ganzzahlen/Zahlen verwenden, machen Sie COL1 immer den niedrigeren Wert und col2 den höheren Wert, wenn Sie die Tabelle ändern oder abfragen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit dba.stackexchange
scroll top