Penso che avete bisogno di affermazioni standard SQL, che sono (purtroppo) largamente non implementato dal DBMS attuali.
Tutte le risposte sono d'accordo che ci sono tre tabelle primarie chiamati TableA, TableB e TableC, ognuna contenente la propria colonna ID:
TableA (A_ID PRIMARY KEY, ...)
TableB (B_ID PRIMARY KEY, ...)
TableC (C_ID PRIMARY KEY, ...)
non è chiaro dalla descrizione del problema se un il singolo valore B può avere più voci padre A. È chiaro che una singola C può avere più voci parent B. Se B è legato ad una singola A, la progettazione di TableB può essere modificata per:
TableB (B_ID, ..., A_ID REFERENCES TableA)
se B può essere associato con diversi A di, allora la connessione è meglio rappresentato da una tabella giunzione:
Inoltre, non è chiaro dalla descrizione se la C associata a una B debba essere uguale per ogni A alla quale la B è associata, o se le diverse A possono fare riferimento allo stesso B e l'insieme di C associate con la B per A1 può essere diverso dal set di C associato alla B per A2. (Naturalmente, se una singola B può essere associata solo ad una A, questo problema è discutibile.)
Ai fini di questa risposta, assumerò che qualsiasi B sia associata a una singola A, quindi la struttura di TableB include A_ID come chiave esterna. Dal momento che un singolo C può essere associato a più B è, la struttura in questione è una nuova tabella che unisce:
B_and_C (B_ID REFERENCES TableB,
C_ID REFERENCES TableC,
PRIMARY KEY (B_ID, C_ID)
)
Semplificando (omettendo regole su deferrability e immediatezza) un'asserzione si presenta come:
CREATE ASSERTION assertion_name CHECK (<search_condition>)
Così , una volta che abbiamo un insieme di decisioni di progettazione, possiamo scrivere un'asserzione per convalidare i dati.tavoli Dato TableA, TableB (con a_id chiave esterna), TableC e B_and_C, il requisito è che il numero di occorrenze di un dato C_ID attraverso una completa A è 1.
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, COUNT(C_ID)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID
HAVING COUNT(C_ID) > 1
)
)
[Modificato: Penso che questo è più preciso:
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, C_ID, COUNT(*)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID, C_ID
HAVING COUNT(*) > 1
)
)
]
l'insieme delle condizioni di unione varia con altre regole per come sono collegati i tavoli, ma la struttura complessiva vincolo rimane la stessa - non ci deve esistere più di un r eferenza a un dato C_ID per un particolare A_ID.
nei commenti qui sotto, note meandmycode:
ho la sensazione che ci sia un difetto nel mio progetto. La mia logica del mondo reale è che una "B" ha sempre almeno un bambino "C". Questo non ha senso dato che "B" deve esistere prima che il suo bambino possa essere attaccato. Il database consentirebbe al momento una "B" di essere collegata a una "A" senza avere almeno UN "C" .. figlio, sto andando così a revisionare "B" in modo che abbia un campo che si riferisce a il suo figlio primario "C", oltre ad avere una raccolta di ulteriori "C", ma ora ho una collezione che potrebbe includere anche la "C" primaria specificata dalla "B", che sarebbe ... errata.
Esiste uno schema di db che potrebbe inferire una regola "uno o più figli", rispetto a zero o più?
Penso che tu abbia problemi con il tuo modello. È difficile creare una B se esiste già una C che si riferisce alla B appena creata, specialmente se C deve riferirsi solo alle B esistenti. Mi viene in mente la frase "pollo e uova". Quindi, normalmente, permetti a B di avere zero o più C in un contesto come questo.
Non hai ancora stabilito se TableB ha una chiave esterna A_ID o se hai una tabella di collegamento come A_and_B. Se ha una chiave esterna, presumibilmente non puoi creare una B finché non hai creato la A alla quale si riferisce.
Non credo che includere un ID C nella tabella B sia una buona idea, rende l'elaborazione asimmetrica (SQL più difficile). Significa anche che se è necessario eliminare quella C, è necessario aggiornare le cose in modo che uno degli altri riferimenti C venga eliminato dalla tabella in cui si trova attualmente, quindi aggiornare il valore nel record B. È disordinato, per essere educato al riguardo.
Penso che sia necessario modificare la domanda per definire la struttura attuale della tabella che si sta guardando - seguendo le linee mostrate in varie risposte; puoi usare i punti tripli per rappresentare colonne diverse ma irrilevanti. L'asserzione che ho suggerito dovrebbe probabilmente essere implementata come una sorta di innesco - che entra nelle notazioni specifiche del DBMS.
Dalla descrizione modificata di memorie (A), osservazioni (B) e soci (C), è chiaro che una singola presentazione si applica a un solo breve, in modo che gli argomenti possono avere una chiave esterna semplice che identifica il brief per cui è una sottomissione. E un membro può collaborare solo su un invio per un particolare brief. Ci sarà una tabella di 'submission_collaborators' con colonne per identificare l'invio e il membro, la combinazione è la chiave primaria e ogni colonna è una chiave esterna.
Briefs(Brief_ID, ...)
Submissions(Submission_ID, Brief_ID REFERENCES Briefs, ...)
Members(Member_ID, ...)
Submission_Collaborators(Submission_ID REFERENCES Submissions,
Member_ID REFERENCES Members,
PRIMARY KEY (Submission_ID, Member_ID)
)
Quindi, il requisito è che la seguente query deve restituire nessuna riga:
SELECT s.brief_id, c.member_id, COUNT(*)
FROM submissions AS s JOIN submission_collaborators AS c
ON s.submission_id = c.submission_id
GROUP BY s.brief_id, c.member_id
HAVING COUNT(*) > 1
Questa è la stessa query che ho inserito nel AFFERMAZIONE CREATE (seconda variante). Puoi estrarre informazioni extra (breve titolo, titolo di presentazione, nome del membro, varie date, ecc.), Ma il nocciolo del problema è che la query mostrata non deve restituire alcun dato.
+1 per volere che il DBMS imponga il vincolo indipendentemente dall'applicazione o dalle applicazioni. –
Sono con Jonathan su questo, troppe persone considerano solo che l'applicazione faccia questo e abbia dati cattivi come risultato. – HLGEM
Come evidenziato dalla mia risposta, il tuo scenario è abbastanza offuscato e se puoi modificarlo, dovresti. Il numero di sistemi che supportano CREATE ASSERTION è molto limitato. La dichiarazione richiesta per verificare i vincoli è complessa da utilizzare in un trigger. –