2009-07-15 2 views
3

Gibt es eine gute Möglichkeit zum Implementieren von Viele-zu-Viele-Beziehungen zwischen Zeilen in einer einzelnen Tabelle?Viele-zu-viele selbstreferentielle Tabelle

Beispiel: Tabelle zum Speichern von Wort Synonyme:

-- list of words 
CREATE TABLE word (
    id integer  PRIMARY KEY, 
    word varchar(32) NOT NULL UNIQUE 
); 
INSERT INTO words (id, word) VALUES (1, 'revolve'); 
INSERT INTO words (id, word) VALUES (2, 'rotate'); 

-- M:M link between words 
CREATE TABLE word_link (
    word1 integer  REFERENCES word(id) NOT NULL, 
    word2 integer  REFERENCES word(id) NOT NULL, 
    PRIMARY KEY (word1, word2) 
); 

Offensichtliche Lösung führt wahrscheinlich nicht-1NF Tabelle enthält doppelte Daten:

INSERT INTO word_link(word1, word2) VALUES (1, 2); 
INSERT INTO word_link(word1, word2) VALUES (2, 1); 

Während Vervielfältigung kann durch Zugabe von (word1 < behandelt werden word2) check, macht SELECTs sehr viel komplexer (union im Vergleich zu trivial join) und ist ziemlich willkürlich. Dieser spezielle Fall kann von der Hilfstabelle profitieren (wie zB "Bedeutung", also sind Wörter M: N mit gemeinsamer Bedeutung und nicht miteinander verbunden, was ein saubereres Schema ergibt), aber ich bin an einer allgemeinen Lösung interessiert.

Gibt es also eine bessere (und hoffentlich gemeinsame) Möglichkeit, eine solche M: M-Beziehung zu implementieren?

Antwort

1

In diesem Fall würde ich eine CHECK CONSTRAINT auf UPDATE und auf INSERT hinzufügen, um zu erzwingen, dass Word1 immer kleiner ist als Word2 und umgekehrt.

0

würde ich eine Ansicht erstellen, die folgenden war:

select distinct 
    case when word1 < word2 then word1 else word2 end as word1, 
    case when word1 < word2 then word2 else word1 end as word2 
from 
    word_link 

Auf diese Weise haben Sie immer eine saubere, keine doppelte Liste, die zur Auswahl einfach ist. Ich habe festgestellt, dass es ungefähr so ​​sauber ist, wie man eine Viele-zu-Viele-Beziehung machen kann.

+0

ummm ... Ihre Case-Anweisung hat die gleichen Kriterien für beide Fälle. Ich nehme an, du meintest word2

+1

@Nathan: Gleiche Bedingung, andere Ergebnisse. Die erste Spalte verwendet immer das kleinere Wort, während die zweite Bedingung immer die größte verwendet. – Eric

+0

ah ich verstehe jetzt –