Specifica di un vincolo univoco bidirezionale su una tabella di join in Postgres

3

Descrizione del problema

Ho una situazione in cui voglio far rispettare che una relazione può essere definita solo una volta e voglio risolverlo a livello di database (Postgres).

La seguente situazione considero non valida, poiché la relazione viene definita due volte.

 user_id | friend_id
---------+-----------
       1 |        35
      35 |         1

Ho provato ad aggiungere CHECK constraints [1] ma non riesco a trovare una condizione che renderà questa situazione non valida. Non sono sicuro di altri modi per gestirlo, senza iniziare a pensare a caratteristiche molto meno trasparenti (come le procedure).

La struttura attuale della tabella:

     Table "public.friends"
  Column   |  Type   | Modifiers
-----------+---------+-----------
 user_id   | integer | not null
 friend_id | integer | not null

Indexes:
    "friends_pkey" PRIMARY KEY, btree (user_id, friend_id)
Check constraints:
    "no_schizophrenia" CHECK (friend_id <> user_id)
Foreign-key constraints:
    "friends_id_key" FOREIGN KEY (friend_id) REFERENCES users(id)
    "user_id_key" FOREIGN KEY (user_id) REFERENCES users(id)

Situazione desiderata

Dati:

 user_id | friend_id
---------+-----------
       1 |        35

Domanda:

insert into friends (user_id, friend_id) values (35, 1) \g

Risultato:

ERROR:  new row for relation "friends" violates check constraint "duplicate_relation"
DETAIL:  Failing row contains (35, 1).

[1] - link

    
posta Dynom 20.07.2016 - 10:42
fonte

1 risposta

0

La tua soluzione è corretta per uno - > molte relazioni in cui ogni utente mantiene la propria lista di amici.

Il secondo record (l'utente # 35 ha l'amico # 1) è corretto per l'utente 35.

Se sei assolutamente intenzionato ad avere un vincolo per implementare un vincolo bidirezionale - Supponendo che la tua one-many join table sia chiamata 'friends', allora penso che assomigli a questo:

CHECK ((friend_id <> user_id) AND (user_id NOT IN (SELECT friend_id FROM friends WHERE user_id = friend_id)))

    
risposta data 30.08.2018 - 21:45
fonte