Relacje w bazie danych - faktury, firmy, umowy

0

Witam
Mam pytanie dotyczące ułożenia relacji w bazie danych. W bazie mamy trzy tabele o nazwie : Firmy, Faktury, Umowy.
Każda faktura ma swojego kontra<ort>ch</ort>enta i może (lecz nie musi) być powiązana z umową. Zakłada się bowiem, że część faktur może być bez umowy (jakieś drobne rachunki itp). Tabele połączyłem relacjami 1:n w sposób jak poniżej:

przykład1.jpg

Zapewne jest źle, gdyż jest ryzyko, że przy dodawaniu faktury może zajść niezgodnośc polegająca na innej firmie w kolumnie firmy i innej firmie wynikającej pośrednio z kolumny umowy?
Myślałem by zrobić prościej np. tak jak poniżej, wówczas do każdej faktury podajemy nr umowy, a firma wynika z tej umowy, tylko jak wówczas dodać faktury które nie mają umowy?

przykład2.jpg

Proszę o info co robię źle i ewentualne wskazówki jak skonstruować tak tą bazę, by spełniała swoje zadanie i była spójna. Z góry proszę o wyrozumiałość ;)
PS. Oczywiście jest to uproszczony schemat, nie pokazałem kolumn typu kwota faktury itp by nie zaciemniać tematu.

1

a może nie ma potrzeby robienia tego w bazie. Niech warunek ten sprawdza aplikacji podczas wprowadzania faktur.

1

Dajesz w umowie pole logiczne który mówi o tym że dana umowa jest wirtualna.
Faktury bez umowy łączysz umową wirtualną, która nigdy nigdzie się nie wyświetla.

0

a ja mam inne pytanie - jeśli w fakturze i na umowie jest INNA firma to jak oba dokumenty mogą dotyczyć TEJ SAMEJ firmy?? No to albo jest ta sama firma albo nie ma umowy i wtedy jest null

0

Dzieki za informacje, być może zrobie tak jak sugerujecie tj program będzie posiadał mechanizm uniemożliwiający wprowadzenie faktury, w której id firmy będzie rozbieżne z firmą z id umowy. Myślałem tylko, ze da się to dodatkowo zabezpieczyć w bazie danych (będzie to SQLite).
Pojawi się tu kolejny problem, mianowicie podczas edycji umowy i zmianie firmy również może być rozbieżność, więc tutaj także program będzie musiał to kontrolować.
Zastanawiam się także nad rozwiązaniem z umową wirtualną, rozumiem że miałoby to wyglądać tak:

przykład3.jpg

W przypadku dodawania faktury bez umowy, program wprowadzałby także automatycznie umowę o polu logicznym True (standardowo byłoby False), która później nie byłaby wyświetlana (chyba że w zestawieniu kosztów pozaumownych itp). Przy usuwaniu faktury, programowo należałoby usunąć również tą wirtualną umowę. Mam nadzieję że to o to chodzi?

0

"Pojawi się tu kolejny problem, mianowicie podczas edycji umowy i zmianie firmy również może być rozbieżność, więc tutaj także program będzie musiał to kontrolować." Nie wiem czy dobrze rozumiem, ale wg mnie najlepiej się zabezpieczyć przed tym w ten sposób, że jeżeli z umową będzie powiązana jakakolwiek faktura program automatycznie zablokuje możliwość zmiany firmy w umowie (lub całą umowę)

0

Żeby nie mnożyć wątków mam kolejne pytanie. Nie wiem co robię źle, ale zapewne rozwiązanie jest banalnie proste.....
Przykład z linkowanej już tu strony http://www.sqlite.org/foreignkeys.html. Tworzę dwie tabele połączone relacją:

 CREATE TABLE artist(
  artistid    INTEGER PRIMARY KEY, 
  artistname  TEXT
);
CREATE TABLE track(
  trackid     INTEGER, 
  trackname   TEXT, 
  trackartist INTEGER,
  FOREIGN KEY(trackartist) REFERENCES artist(artistid)
); 

Zgodnie z przykładem ze strony, przy próbie dodania utworu z nieistniejącym artystą:

INSERT INTO track VALUES(14, 'Mr. Bojangles', 3); 

powinien wyskoczyć error:

SQL error: foreign key constraint failed

W moim przypadku rekord najzwyczajniej w świecie dodaje się do bazy, zarówno przy ręcznym wpisaniu polecenia SQL w programie, jak i gdy otworzę plik bazy w SQLite Manager i tam dodaję rekord...Dlaczego ?

1

a włączyłeś obsługę kluczy obcych? - PRAGMA foreign_keys = ON;

0

Włączyłem obsługę kluczy obcych zgodnie z zaleceniami z tej strony

http://www.lazarus.freepascal.org/index.php?topic=15477.0

tj. dodałem do TSQLite3Connection.Params parametr: foreign_keys=on.

Niestety ograniczenie nadal nie działa i można dodawać rekordy z niespójnymi kluczami.

 Form1.SQLQuery1.SQL.Clear;
Form1.SQLQuery1.SQL.Add(edit1.Text);
Form1.SQLQuery1.ExecSQL;
Form1.SQLTransaction1.Commit;

Mam najnowszą wersję pliku sqlite.dll (3.7.17). Problem tkwi najprawdopodobniej w w/w ustawieniach w Lazarusie - męczę się z tym już pół dnia i nic...

0

ale biblioteka musi być odpowiednio skompilowana - http://www.sqlite.org/foreignkeys.html#fk_enable

0

Tuż po połączeniu spróbuj dać:

Form1.SQLQuery1.SQL.Text:='PRAGMA foreign_keys = ON';
Form1.SQLQuery1.ExecSQL;
0

Spróbowałem:

 
Form1.SQLQuery1.SQL.Clear;
Form1.SQLQuery1.SQL.Text:='PRAGMA foreign_keys = ON';
Form1.SQLQuery1.ExecSQL;
Form1.SQLQuery1.SQL.Text:=edit1.Text;
Form1.SQLQuery1.ExecSQL;
Form1.SQLTransaction1.Commit;

Nadal nic. Mam nadzieje, że to nie kwestia skompilowania biblioteki sqlite3, bo nawet nie wiem jak się za to zabrać.

0

Na przyszłość dla innych użytkowników Lazarusa - problem z włączeniem kluczy obcych leżał po stronie programu, przy aktualizacji Lazarusa do wersji 1.10 sam się rozwiązał. Teraz obsługa kluczy śmiga jak należy :) Należy tylko pamiętać o dodaniu do TSQLite3Connection.Params parametru: foreign_keys=on. W programie wykorzystałem wskazówki _13th_Dragon. Dzięki za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1