12

Ho una struttura a tre tabelle: tournament, group e team. Le tabelle tournament e group avere un rapporto uno-a-molti e group e team avere un rapporto uno-a-molti come mostrato di seguito.Come replicare la chiave esterna di un'altra tabella in relazione uno a molti

table structure

Come si replica il valore del tournament_id da group tabella nella group_tournament_id di team tavolo?

sto cercando una risposta che raggiungere questo obiettivo utilizzando l'istruzione CREATE come

create table team (
    id serial primary key, 
    group_id int references group, 
    group_tournament_id int references group(tournament_id) 
); 

naturalmente questo non avrebbe funzionato perché per fare riferimento a qualcosa che deve essere unico, in questo caso è tournament_id non unico

ho bisogno di un modo standard per copiare il valore di tournament_id da group nella 'squadra' il tavolo di group_tournament_id quando mai inserisco group_id inside squadra table

modifica: non è più necessaria la risposta in symfony, solo postgreSQL andrebbe bene

+0

Ecco come relazionare le entità: http: //doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/association-mapping.html e qui symfony docs sulla mappatura: http: //symfony.com/doc/current/book/doctrine.html#add-mapping-information – fito

+1

Penso che sarebbe d'aiuto se la tua domanda fosse un po 'più specifica in quello che stai cercando di fare e contenesse del codice che potresti avere provato. –

+3

Normalmente, la tabella 'team' dovrebbe avere solo' group_id' e dovrebbe ** not ** avere 'tournament_id' affatto. Non capisco perché tu de-normalizzi il tuo schema. –

risposta

5

È necessario utilizzare il riferimento direttamente da teams a tournaments. Utilizzare un trigger per ottenere automaticamente il riferimento appropriato da groups. (nota comunque che il riferimento non è necessario in quanto è sempre possibile ottenere tournament_id da groups in una query. Suppongo che questo riferimento sia per semplificare alcune query).

Ho leggermente modificato i nomi di tabelle e colonne (group non può essere un nome di tabella).

Tabelle:

create table tournaments (
    tournament_id serial primary key); 

create table groups (
    group_id serial primary key, 
    tournament_id int references tournaments); 

create table teams (
    team_id serial primary key, 
    group_id int references groups, 
    tournament_id int references tournaments); 

trigger:

create or replace function before_insert_or_update_on_teams() 
returns trigger language plpgsql as $$ 
begin 
    new.tournament_id = (
     select tournament_id 
     from groups 
     where group_id = new.group_id 
     limit 1); 
    return new; 
end $$; 

create trigger before_insert_or_update_on_teams 
before insert or update on teams 
for each row execute procedure before_insert_or_update_on_teams(); 

prova:

insert into tournaments values (default), (default); 
insert into groups values (default, 2); 
insert into teams values (default, 1, null); 

select * from teams; 

team_id | group_id | tournament_id 
---------+----------+--------------- 
     1 |  1 |    2 
(1 row) 
+0

in altri modi per ottenere questo risultato senza trigger? OP ha chiesto alternative ai trigger – Dheeraj

+1

Oh, sì, non ho letto la nota di bounty. Se l'avessi visto non avrei postato la risposta. Ma ... cosa c'è che non va con un grilletto? Questa è la soluzione più naturale e standard in casi come questo. – klin

3

si può semplicemente utilizzare identificare relazioni:

enter image description here

Questo produce chiavi che "si propagano" completamente verso il basso, in modo da ottenere team.tournament_id che è garantito per puntare allo stesso torneo del gruppo genitore.

Nota che ho utilizzato group_no (non group_id) come convenzione di denominazione per indicare che non identifica il gruppo da solo, ma in combinazione con lo tournament_id. Idem per team_no.

Questo complica l'inserimento, però. Non puoi semplicemente lasciare che il database generi il prossimo ID auto-incrementato per il tuo gruppo o team (perché ora lo stai identificando con una combinazione di valori, non solo un valore), ma puoi farlo facilmente manualmente - ad es.quando si inserisce in group, assegnare SELECT MAX(group_no) + 1 FROM group WHERE tournament_id = ... al nuovo group_no e simili per il team.

BTW, questo può essere fatto in aggiunta -surrogate keys (il id nel diagramma), se ancora bisogno di loro.

1

è possibile utilizzare un SELECT per alimentare un valore con INSERT o UPDATE:

INSERT INTO "teams" ("group_id", "tournament_id") 
SELECT $1, "groups"."tournament_id" 
    FROM "groups" WHERE ("groups"."id" = $1) 
RETURNING "id" 

Questo è quello che sto usando per far Postgres inserire gli ID per le chiavi esterne senza il (unconsistent) doppia query (selezionare da gruppi , inserire in squadre).