myślę, że trzeba SQL standardowych twierdzeń, które są (niestety) w dużej mierze wdrożone przez rzeczywistych DBMS.
wszystkie odpowiedzi są zgadzając się, że istnieją trzy tabele zwane podstawowe TABLEA, TableB i TableC, każdy zawierający własną kolumna ID:
TableA (A_ID PRIMARY KEY, ...)
TableB (B_ID PRIMARY KEY, ...)
TableC (C_ID PRIMARY KEY, ...)
nie jest jasne na podstawie poniższego opisu problemu czy dany pojedyncza wartość B może mieć wiele wpisów nadrzędnych A. Oczywiste jest, że pojedynczy C może mieć wiele wpisów nadrzędnych B. Jeśli B jest przywiązany do jednego A, projekt TableB może zostać zmieniona w celu:
TableB (B_ID, ..., A_ID REFERENCES TableA)
jeśli B może wiązać się z kilkoma różnymi, wtedy połączenie jest najlepiej reprezentowana przez tabelę łączącą:
A_and_B (A_ID REFERENCES TableA,
B_ID REFERENCES TableB,
PRIMARY KEY (A_ID, B_ID)
)
Z opisu nie wynika też, czy litery C związane z literą B muszą być takie same dla każdego A, z którym B jest powiązane, czy też różne A mogą odwoływać się do tego samego B, a zbiór C jest powiązany z B dla A1 może się różnić od zestawu C związanych z B dla A2. (Oczywiście, jeśli pojedynczy B może być powiązany tylko z jednym A, ten problem jest dyskusyjny.)
Dla celów tej odpowiedzi, zakładam, że dowolne B jest powiązane z pojedynczym A, więc struktura TableB zawiera A_ID jako klucz obcy. Ponieważ pojedynczy C może być powiązany z wieloma B, odpowiednia struktura jest nowa tabela łączenia:
B_and_C (B_ID REFERENCES TableB,
C_ID REFERENCES TableC,
PRIMARY KEY (B_ID, C_ID)
)
Uproszczenie (pomijając zasady dotyczące deferrability i bezpośredniości) twierdzenie wygląda następująco:
CREATE ASSERTION assertion_name CHECK (<search_condition>)
Tak , kiedy już mamy zestaw decyzji projektowych, możemy napisać potwierdzenie do sprawdzenia poprawności danych.Biorąc pod uwagę, stoły TABLEA, TableB (z kluczem A_ID obcej), TableC i B_and_C wymóg jest taki, że liczba wystąpień danego C_ID całej kompletnej A jest 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
)
)
[Zmieniony: Myślę, że to jest bardziej precyzyjne:
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
)
)
]
zestaw dołączyć warunki zmienia się wraz z innymi przepisami na jak tabele są połączone, ale ogólna struktura ograniczeniem pozostaje ten sam - nie musi istnieć więcej niż jeden R odniesienie do danego C_ID dla określonego A_ID.
w komentarzach poniżej, meandmycode Uwagi:
mam wrażenie, że nie jest to wada w moim projekcie. Moją prawdziwą logiką jest to, że "B" zawsze ma co najmniej jedno dziecko "C". Nie ma to sensu, ponieważ "B" musi istnieć, zanim będzie można przywiązać dziecko. Baza danych obecnie zezwala na dołączenie "B" do "A" bez posiadania co najmniej JEDNEGO "C" .. dziecko, ja jako taki zmieniam "B" tak, że ma ono pole, które odnosi się do jego pierwotne dziecko "C", a także dziecko z dodatkowymi "C", ale teraz mam kolekcję, która może również zawierać pierwotne "C" określone przez "B", co byłoby ... błędne.
Czy istnieje wzór bazy danych, który wskazywałby zasadę "jeden lub więcej dzieci", a nie zero lub więcej?
Myślę, że masz problemy z modelem. Trudno jest utworzyć B, jeśli musi już istnieć C, który odnosi się do nowo utworzonego B, zwłaszcza jeśli C musi odnosić się tylko do istniejących B. Na myśl przychodzi zwrot "kurczak i jajko". Zwykle pozwalasz, aby B miały zero lub więcej C w takim kontekście.
Wciąż nie ustalono, czy tabela B ma klucz obcy A_ID, czy też ma tabelę łączącą, taką jak A_i_B. Jeśli ma klucz obcy, to prawdopodobnie nie możesz utworzyć B, dopóki nie stworzysz A, do którego się odnosi.
Nie sądzę, aby jeden C ID w tabeli B był dobrym pomysłem - powoduje to asymetryczne przetwarzanie (trudniejszy SQL). Oznacza to również, że jeśli chcesz usunąć ten C, musisz zaktualizować rzeczy tak, aby jedno z pozostałych odwołań C zostało usunięte z tabeli, w której się aktualnie znajduje, a następnie zaktualizować wartość w rekordzie B. To niechlujne, być grzecznym.
Myślę, że trzeba poprawić swoje pytanie, aby zdefiniować rzeczywistą strukturę tabeli, którą oglądasz - zgodnie z liniami przedstawionymi w różnych odpowiedziach; możesz użyć potrójnych kropek do przedstawienia innych, ale nieistotnych kolumn. Twierdzenie, które zasugerowałem, prawdopodobnie musiałoby zostać zaimplementowane jako pewien rodzaj wyzwalacza - który dostaje się do notacji specyficznej dla systemu DBMS.
Od zmienionym opisem majtek (A), zgłoszeń (B) i członków (C), jest oczywiste, że pojedyncza złożenie dotyczy tylko jeden krótki, tak, że wnioski mogą mieć prosty klucz obcy że określa brief, dla którego jest składany. Członek może współpracować tylko przy jednym zgłoszeniu na dany brief. Zostanie wyświetlona tabela "submission_collaborators" z kolumnami do identyfikacji zgłoszenia i członka, kombinacja jest kluczem podstawowym, a każda kolumna jest kluczem obcym.
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)
)
Stąd, wymaga się, aby po musi zwrócić nie rzędach
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
To samo zapytanie, że osadzony na stwierdzeniu stworzyć (drugi wariant). Możesz również uzyskać dodatkowe informacje (krótki tytuł, tytuł zgłoszenia, nazwę członka, różne daty itp.), Ale sedno problemu polega na tym, że przedstawione zapytanie nie może zwracać żadnych danych.
+1 za to, że DBMS ma egzekwować ograniczenie, niezależnie od tego, co robią aplikacje. –
Jestem z Jonathanem na ten temat, zbyt wiele osób bierze pod uwagę tylko to, że aplikacja wykonuje tę pracę i ma złe dane. – HLGEM
Jak dowodzi moja odpowiedź, twój scenariusz jest dość zaciemniony i jeśli możesz go zmienić, powinieneś. Liczba systemów obsługujących CREATE ASSERTION jest bardzo ograniczona. Instrukcja wymagana do sprawdzenia ograniczeń jest skomplikowana do użycia w wyzwalaczu. –