2010-08-29 15 views
6

Sto postando questa domanda che è in qualche modo un riassunto del mio altro question.unica coppia in un database "amicizia"

ho due banche dati:
1) db_users.
2) db_friends.

Sottolineo che sono memorizzati in database separati su server diversi e pertanto non è possibile utilizzare chiavi esterne.

in 'db_friends' Ho l' 'tbl_friends' tabella che ha le seguenti colonne:
- id_user
- id_friend

Ora come faccio a fare in modo che ogni coppia è unica a questo tavolo ('tbl_friends')?
Mi piacerebbe farlo a livello di tabella e non attraverso una query.

Per esempio Queste sono le righe non valide:
1-2
2-1

mi piacerebbe che ciò è impossibile da aggiungere.

Inoltre - come faccio a seach per tutti gli amici di utente 713 mentre avrebbe potuto essere menzionato, su alcune righe di amicizia, alla seconda colonna ('id_friend')?

risposta

6

Probabilmente non riuscirai a farlo a livello di database - il codice dell'applicazione dovrà farlo. Se ti assicuri che i tuoi record di tbl_friends entrino sempre con (lowId, highId), allora un tipico indice PK/Unique risolverà il problema dei duplicati. In effetti, andrei così lontano per rinominare le colonne nel tuo tbl_friends in (id_low, id_high) solo per rinforzarlo.

Vostri criteri di trovare qualcosa con l'utente 713 sarebbe poi essere qualcosa come

SELECT id_low AS friend FROM tbl_friends WHERE (id_high = ?) 
UNION ALL 
SELECT id_high AS friend FROM tbl_friends WHERE (id_low = ?) 

Per l'efficienza, si sarebbe probabilmente desidera indicizzare in avanti ed indietro - cioè da (id_user, id_friend) e (id_friend, id_user).

Se si fare questo a livello di DB, quindi una stored procedure per scambiare argomenti a (basso, alto) prima dell'inserimento funzionerebbe.

1

Bene, un vincolo univoco sulla coppia di colonne vi porterà a metà strada lì. Penso che il modo più semplice per assicurarti di non ottenere la versione invertita sarebbe di aggiungere un vincolo assicurando che id_user < id_friend. Dovrai compensare questo ordine al momento dell'inserimento, ma otterrai il vincolo di livello del database che desideri senza duplicare i dati o affidarti a chiavi esterne.

Per quanto riguarda la seconda domanda, per trovare tutti gli amici per id = 1 è possibile selezionare id_user, id_friend da tbl_friend dove id_user = 1 o id_friend = 1 e quindi nel codice client eliminare tutti gli 1 indipendentemente dalla colonna.

3

Dovresti utilizzare un trigger per applicare la regola aziendale.
Fare in modo che le due colonne in tbl_friends la chiave primaria (il vincolo unico non lo consenta) garantirebbe solo che non possano essere duplicati dello stesso insieme: 1, 2 può apparire solo una volta ma 2, 1 sarebbe valido.

come farei a cercare tutti gli amici dell'utente 713 mentre potrebbe essere menzionato, in alcune file di amicizia, nella seconda colonna ('id_friend')?

È possibile usare un IN:

WHERE 713 IN (id_user, id_friend) 

..o un UNION:

JOIN (SELECT id_user AS user 
     FROM TBL_FRIENDS 
     UNION ALL 
     SELECT id_friend 
     FROM TBL_FRIENDS) x ON x.user = u.user 
+0

Grazie per la risposta! Quale delle query sopra è migliore in termini di prestazioni? – Poni

+0

@Poni: consiglio sempre di controllare il piano di ricerca/query per il proprio sistema per vedere quale è il migliore. –

0

Un modo che si possa fare è quello di memorizzare i due amici su due file:

CREATE TABLE FriendPairs (
    pair_id INT NOT NULL, 
    friend_id INT NOT NULL, 
    PRIMARY KEY (pair_id, friend_id) 
); 

INSERT INTO FriendPairs (pair_id, friend_id) 
VALUES (1234, 317), (1234, 713); 

Vedere? Non importa in quale ordine li inserisci, perché entrambi gli amici vanno nella colonna friend_id. Quindi puoi forzare facilmente l'unicità.

È possibile anche interrogare facilmente per gli amici di 713:

SELECT f2.friend_id 
FROM FriendPairs AS f1 
JOIN FriendPairs AS f2 ON (f1.pair_id = f2.pair_id) 
WHERE f1.friend_id = 713 
+0

Grazie per aver dedicato del tempo a rispondere a Bill - beh, questo sembra implicare troppi sovraccarichi - sia dalla quantità di aspetto delle righe (doppia dimensione) sia dall'aspetto della query in cui ho bisogno di unire e cose .. I'd Meglio mettere un vincolo (id_user Poni

+0

@Poni: No, non sarebbe d'aiuto. Se hai coppie come (137,317) e (317,713), l'utente 317 può ancora finire nella prima o nella seconda colonna anche se hai forzato 'id_user