2013-03-22 11 views
5
CREATE TABLE nodes (
     id INTEGER PRIMARY KEY, 
     name VARCHAR(10) NOT NULL, 
     feat1 CHAR(1), -- e.g., age 
     feat2 CHAR(1) -- e.g., school attended or company 
    ); 

    CREATE TABLE edges (
     a INTEGER NOT NULL REFERENCES nodes(id) ON UPDATE CASCADE ON DELETE CASCADE, 
     b INTEGER NOT NULL REFERENCES nodes(id) ON UPDATE CASCADE ON DELETE CASCADE, 
     PRIMARY KEY (a, b) 
    ); 

    CREATE INDEX a_idx ON edges (a); 
    CREATE INDEX b_idx ON edges (b); 

Jeśli chcemy reprezentować nieukierunkowany wykres, musimy dodać ograniczenie CHECK na unikatowości pary.Mysql: Jak sprawdzić wyjątkowość pary

Ponieważ standard SQL nie zezwala na podkwerendy w ograniczeniu CHECK, Jak mogę sprawdzić unikalność pary?

+0

Po prostu wyjaśniając - celem jest zapobieganie np. oba (1, 2) _i_ (2, 1) z pojawienia się w tabeli - czy to prawda? –

+0

tak, to prawda. Również nie powinno być żadnych pętli własnych. –

Odpowiedz

3

MySQL nie obsługuje ograniczeń CHECK.

Możesz utworzyć PRZED WSTAWIENIEM i PRZED AKTUALIZACJĄ wyzwalasz, aby sprawdzić tę sytuację, i w razie potrzeby wyślij błąd.

Przykład:

CREATE TABLE edges(
    a INT(11) NOT NULL, 
    b INT(11) NOT NULL 
); 

DELIMITER $$ 

CREATE TRIGGER trigger1 
BEFORE INSERT 
ON edges 
FOR EACH ROW 
BEGIN 
    SET @cnt = NULL; 

    SELECT COUNT(*) INTO @cnt FROM edges 
    WHERE a = new.a AND b = new.b OR a = new.b AND b = new.a; 

    IF @cnt > 0 THEN 
    SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Error: uniqueness of pair'; 
    END IF; 
END 
$$ 

DELIMITER ; 

także stworzyć podobny PRZED UPDATE wyzwalacz do uniknięcia nowych błędne wartości na aktualizację, lub po prostu skorzystać z procedury przechowywanej, ponieważ kod jest taki sam.

2

CHECK nie jest obsługiwana w CREATE TABLE przez MySQL, jak documentation dyktuje

Klauzula KONTROLA jest analizowany, ale ignorowane przez wszystkich silników składowania

W rzeczywistości istnieje open bug report w tej kwestii, ponieważ 2004 (!).

Podejście, które chciałbym podjąć, to utworzenie wyzwalacza procedury przechowywanej przy wstawianiu i przy aktualizacji, które celowo się nie powiedzie, jeśli para istnieje.

7

Można by sklecić wyzwalacz, który nie działa widząc albo (A,B) lub (B,A):

Oto wyzwalania:

DELIMITER $$ 
CREATE TRIGGER edges_bi BEFORE INSERT 
ON edges FOR EACH ROW 
BEGIN 
    DECLARE found_count,dummy,diff,SomethingsWrong INT DEFAULT 0; 
    DECLARE errmsg VARCHAR(128); 
    SET diff = new.a - new.b; 
    IF diff = 0 THEN 
     SET errmsg = CONCAT('[',new.a,',',new.b,'] is Vertex, Not Edge'); 
     SET SomethingsWrong = 1; 
    END IF; 
    SELECT COUNT(1) INTO found_count FROM edges 
    WHERE (a=NEW.a AND b=NEW.b) OR (a=NEW.b AND b=NEW.a); 
    IF found_count = 1 THEN 
     SET errmsg = CONCAT('[',new.a,',',new.b,'] Already Exists'); 
     SET SomethingsWrong = 1; 
    END IF; 
    IF SomethingsWrong = 1 THEN 
     SELECT errmsg INTO dummy FROM edges WHERE 1=1; 
    END IF; 
END; $$ 
DELIMITER ; 

Oto tabela próbki:

DROP DATABASE if exists saurabh; 
CREATE DATABASE saurabh; 
USE saurabh 
CREATE TABLE edges 
(
    a INTEGER NOT NULL, 
    b INTEGER NOT NULL, 
    PRIMARY KEY (a,b), 
    UNIQUE KEY (b,a) 
); 

Zauważmy, że Mam klucz podstawowy i klucz UNIQUE z kolumnami klucza podstawowego odwrócony

Stwórzmy tabelę:

mysql> DROP DATABASE if exists saurabh; 
Query OK, 1 row affected (0.01 sec) 

mysql> CREATE DATABASE saurabh; 
Query OK, 1 row affected (0.00 sec) 

mysql> USE saurabh 
Database changed 
mysql> CREATE TABLE edges 
    -> (
    -> a INTEGER NOT NULL, 
    -> b INTEGER NOT NULL, 
    -> PRIMARY KEY (a,b), 
    -> UNIQUE KEY (b,a) 
    ->); 
Query OK, 0 rows affected (0.12 sec) 

mysql> 

Stwórzmy Trigger:

mysql> DELIMITER $$ 
mysql> CREATE TRIGGER edges_bi BEFORE INSERT 
    -> ON edges FOR EACH ROW 
    -> BEGIN 
    ->  DECLARE found_count,dummy,diff,SomethingsWrong INT DEFAULT 0; 
    ->  DECLARE errmsg VARCHAR(128); 
    ->  SET diff = new.a - new.b; 
    ->  IF diff = 0 THEN 
    ->   SET errmsg = CONCAT('[',new.a,',',new.b,'] is Vertex, Not Edge'); 
    ->   SET SomethingsWrong = 1; 
    ->  END IF; 
    ->  SELECT COUNT(1) INTO found_count FROM edges 
    ->  WHERE (a=NEW.a AND b=NEW.b) OR (a=NEW.b AND b=NEW.a); 
    ->  IF found_count = 1 THEN 
    ->   SET errmsg = CONCAT('[',new.a,',',new.b,'] Already Exists'); 
    ->   SET SomethingsWrong = 1; 
    ->  END IF; 
    ->  IF SomethingsWrong = 1 THEN 
    ->   SELECT errmsg INTO dummy FROM edges WHERE 1=1; 
    ->  END IF; 
    -> END; $$ 
Query OK, 0 rows affected (0.11 sec) 

mysql> DELIMITER ; 

Oto przykładowe dane:

INSERT INTO edges (a,b) VALUES (5,3); 
INSERT INTO edges (a,b) VALUES (3,3); 
INSERT INTO edges (a,b) VALUES (3,5); 
INSERT INTO edges (a,b) VALUES (5,5); 
SELECT * FROM edges; 

Spróbujmy ładuje je do tabeli edges:

mysql> INSERT INTO edges (a,b) VALUES (5,3); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO edges (a,b) VALUES (3,3); 
ERROR 1366 (HY000): Incorrect integer value: '[3,3] is Vertex, Not Edge' for column 'dummy' at row 1 
mysql> INSERT INTO edges (a,b) VALUES (3,5); 
ERROR 1366 (HY000): Incorrect integer value: '[3,5] Already Exists' for column 'dummy' at row 1 
mysql> INSERT INTO edges (a,b) VALUES (5,5); 
ERROR 1366 (HY000): Incorrect integer value: '[5,5] is Vertex, Not Edge' for column 'dummy' at row 1 
mysql> SELECT * FROM edges; 
+---+---+ 
| a | b | 
+---+---+ 
| 5 | 3 | 
+---+---+ 
1 row in set (0.00 sec) 

Zauważ, że blokowanie A = warunki B zapobiega z własnym pętle

CAVEAT

Ten wyzwalacz nie działa, jeśli

  • zaczynasz z pustą tabelą
  • wprowadzić (3,3) w pierwszym rzędzie

ponieważ wyzwalacz BEFORE INSERT nie uruchamia się przy pustym stole.

Po wprowadzeniu prawidłowego wiersza z A <> wszystkie kontrole zostaną wykonane poprawnie.

Spróbuj!

+0

Czy otrzymam nagrodę ??? – RolandoMySQLDBA

0

Myślę, że odpowiedź może zależeć od sposobu wypełniania tabeli edges, co nie wynika z twojego pytania. Jeśli jest wypełniany z tabeli nodes, może być możliwe utworzenie WIDOKU na podstawie zapytania SELECT, które wyklucza pary lustrzane (tj. 1,2 i 2,1). Może to również rozwiązać wymóg kaskady i usuwania.

Powiązane problemy