PDA

Vollständige Version anzeigen : Datenintegrität bei Vermeidung zusammengesetzer Primärschlüssel


WeinGeist
24.04.2009, 09:52
Hallo Leute,

Wie seht ihr das? Wie setze ich die geforderte Datenintegrität auch wirklich durch?

Einfaches Szenario:

Mal ein vereinfachtest Datenmodell zu besseren Veranschaulichung:

tblAuftrag
- AuftragID (PK)
- FKKundeID

tblAuftragPos
- AuftragPosID (PK)
- FKAuftragID
- BestellteMenge

tblRechnungen
- RechnungID (PK)
- FKKundeID

tblRechnungenPos
- RechnungPosID (PK)
- FKRechnungID
- FKAuftragPosID
- GelieferteMenge

Die Problematik ist hier, dass auf Datenbankebene nicht sichergestellt ist, dass KundeID in Auftrag und KundeID in Rechnungen auch wirklich identisch ist.

Ein mögliche Lösung wäre jeweils die KundenID in die Pos-Tabelle durchreichen und mehrstufige PK's/Indexes verwenden und Verknüpfungen erstellen.

Dagegen spricht, dass das Ganze immer komplexer wird, da schnell mal Schlüssel mit vielen Spalten anstehen.

Bei Verwendung von "EinerSchlüssel" besteht aber die Gefahr von:
- Fehlmanipulationen durch Abfragen
- Fehler in der Programmierung von Erfassen, ändern, löschen
- Fehler bei Wartungsarbeiten

Mögliche Lösung wäre die Verwendung von einem aktiven DB-System wie SQL-Server und damit StoredProcedures für solche Aktionen. Bei Wartungsarbeiten ist man davor aber auch nicht durch das DB-System geschützt.

Zum Schluss: Wie geht ihr mit dieser Problematik um?

Wäre schön ein paar Statements dazu zu bekommen. Ich persönlich verwende ausschliesslich "einfache" Verlinkungen und stelle die effektive Integrität in Access lediglich auf Applikationsebene sicher.

Atrus2711
24.04.2009, 10:04
Grundsatzdiskussion am Freitag *banzai*

Ich sehe das so:
Ein Primärschlüssel soll eindeutig und kurz sein. Wenn man zusammengesetzte Keys verwendet, kann man die dazu "missbrauchen", auch Duplikate zu verhindern (was "nur" eine fachliche Anforderung ist), aber du siehst, dass das später aufwendig werden kann.

Die Duplikateverhinderung kann aber auch ein eindeutiger Index sicherstellen. Das hat mit dem PK nichts zu tun, das ist eine Nebenbedingung (constraint).

Und dann ist eben beides möglich:

ein Autowert/GUID, der datenbanktechnisch als Ein-Feld-Key fungiert und ein leichtes Verlinken zu anderen Tabellen ermöglicht,
und ein eindeutiger Index, der die Duplikate verhindert, aber eben kein PK ist.


:)

Duplikatverhinderung nur auf Applikationsebene hat alelrdings den Nachteil, dass man bei Massenoperationen im Backend leicht Dinge eintragen kann, die unzulässig sind. Das Frontend kümmert sich bei zwar auch um "Nebenläufigkeiten", aber nicht um die Duplikatverhinderung.


Ceterum censeo: Keys should not be natural: http://www.informit.com/articles/article.aspx?p=170821
Ich hab da schon Pferde kotzen sehen. Ich habe hier z.B. eine Konvertierungstabelle von ISO-Währungscodes (USD, GBP, ...) in einen Firmeninternen Schlüssel (400 = USD). Leider haben die Spezis nicht mitbekommen, dass die Türkei vor einiger Zeit ein paar Nullen gestrichen hat, und hat den gleichen Nummernkey für die alte wie die neue Türkische Lira vergeben. Das gab vielleicht einen Kurssprung beim Lirechart... :) Man kann hier natürlich diskutieren, was eigentlich noch gleich bleibt, wenn man Nullen streicht. Der Name, ok. Aber sonst auch nix; vergleichbar sind die nicht mehr. Letztlich sind Altlire und Neulire nur "zufällig" gleichnamig, so wie ja auch zwei Thomas Meiers in meiner Kundentabelle "zufällig" den gleichen Namen haben. Das heißt aber nix.

gpswanderer
24.04.2009, 10:06
Hallo,
das Modell hat nach meiner Auffassung einen kleinen Fehler. In die Rechnung gehört die AuftragID und nicht die KundenID. Denn die Rechnung ist vom Auftrag abhängig. Ohne Auftrag > keine Rechnung.

tblRechnungen
- RechnungID (PK)
- AuftragID

Die Problematik ist hier, dass auf Datenbankebene nicht sichergestellt ist, dass KundeID in Auftrag und KundeID in Rechnungen auch wirklich identisch ist.
Damit ist diese Problematik erledigt.

Josef P.
24.04.2009, 10:09
Ich würde es vermutlich so wie du machen und auf den 2er-FK verzichten. Außerdem: warum soll Kunde A nicht auch mal den Auftrag für Kunde B bezahlen? ;)

Mögliche Lösung wäre die Verwendung von einem aktiven DB-System wie SQL-Server und damit StoredProcedures für solche Aktionen. Bei Wartungsarbeiten ist man davor aber auch nicht durch das DB-System geschützt.
Insert/Update-Trigger finde ich für den beschriebenen Fall praktischer.

In die rechnung gehört die AuftragID und nicht die KundenID.
... wenn je Auftrag eine Rechnung geschrieben wird. Wenn eine Rechnung mehrere Aufträge bzw. Auftragspositionen enthalten kann, sieht das vielleicht anders aus.
Aber du hast schon Recht: auch in so einem Fall ist die Kunden-Kennung doppelt vorhanden, da sie über die Auftragspositionen ermittelt werden könnte.
Aber: vielleicht gibt es auch eine Rechnung ohne Auftrag? ... dann muss die Kundenkennung doch wieder im Rechnungskopf stehen. usw.

Anm.: ich nehme an, das Beispiel von Urs soll erstmal nur das Problem beschreiben, dass man oftmals nur per Mehrfelder-FK Datenkonsistenz in Jet-Tabellen sicherstellen kann.

WeinGeist
24.04.2009, 10:12
@Atrus: Für Duplikate sehr einfach. Stelle ich auch per Index sicher. Aber bei diesem Szenario?

@wanderer: Klar, in diesem Fall kann man das durchaus so machen (Wenn man das möchte). Es geht mir ja eigentlich um das Prinzip, da es ja manchmal nicht möglich ist und die Flexibilität gefordert wird.

@Josef: Ganz genau erfasst. ;)

Atrus2711
24.04.2009, 10:52
Ein anderes Beispiel:

Sprachkenntnisse von Mitarbeitern (Auflösung einer m:n-Beziehung zwischen tblMitarbeiter und tblSprache).

Wenn man postuliert: "Ein Mitarbeiter hat in einer Sprache genau einen Kenntnisstand" (z.B. Atrus kann Deutsch in Stufe 10), dann könnte man F_Sprache und F_Mitarbeiter gemeinsam zum PK machen und den Kenntnisstand (Zahl) als Nichtschlüsselfeld in der Tabelle halten, denn es kann nicht sein, dass derselbe Mann dieselbe Sprache in mehreren Kenntnisgraden beherrscht: entweder bin ich gut in Deutsch oder schlecht in Deutsch, aber nicht beides.

Nun entwickelt sich da Modell aber vielleicht weiter. Man will vielleicht später die Sprachkenntnisse in Wort und Schrift unterscheiden. Und da kann es dann durchaus sein, dass derselbe Mann dieselbe Sprache "zweimal" kann, nämlich einmal in Wort (z.B Stufe 7) und einmal in Schrift (Stufe 10).

Wer bisher einen Autowert/GUID als Key verwendet hat, hat kein problem damit und muss "nur" den UniqueIndex ändern. Wer aber mit F_Sprache und F_Mitarbeiter als zusammenesetztem Key gearbeitet hat, hat jetzt eine Keyänderung am Hals, die sich durch nachgeordnete Tabellen durchzieht.

WeinGeist
24.04.2009, 13:35
Mir geht es noch ned mal zwingend darum ob nun das Daten-Modell für genau diesen Fall sinnvoll ist oder eben nicht, sondern viel eher ob ihrs einfach oder eben komplex verlinken würdet oder eben KundenID jeweils in die Pos-Tabelle zu verlinken und dann über PosID UND KundenID zu verlinken. Sprich um jeden Fall die vollständige Integrität per DB wahren oder eben nicht.

Habe mal versucht ein etwas sinnvolleres Beispiel zu nehmen, wo die Anforderungen klarer sein dürften. Habe ein stark vereinfachtes Modell einer Warenbuchhaltung + Produktion genommen und im Anhang zwei Grafiken angefügt. Einmal ein "einfaches" Modell und einmal ein "Komplexes" mit voller Integrität auf Tabellenebene.

Ein paar Aussagen dazu:
- Es gibt Buchungen, die ohne irgendwelche Produktionen laufen. Auslieferungen, Anlieferungen usw.
- Bei einem Arbeitsschritt müssen die OutCharge + InputCharge zwingend identisch sein.

Die Konkrete Frage:
- Lässt sich dieser Fall in einem aktiven DB-System gänzlich abbilden via Variante 1 über Trigger? @Josef :p
- Was bleibt mir in Access? Auf Applikationslevel sicherstellen oder komplex verwenden?

Josef P.
24.04.2009, 14:02
So richtig verstanden hab ich das Modell bzw. deinen Wunsch nicht. ;)
Bei einem Arbeitsschritt müssen die OutCharge + InputCharge zwingend identisch sein.
"Mischen" ist also kein Arbeitsschritt?

Entspricht die Tabelle "tblBuchungen" einer Art "Stückliste"?
... ChargeOut besteht aus n ChargeIn und ChargeOut wird über n tblProdArbeitsschritt produziert?
Wäre dann eventuell so etwas denkbar:
42957

WeinGeist
24.04.2009, 14:05
Hab noch eins.... OK oben nicht so sinnig, habe etwas falsch zusammengekürzt.

@Josef: EDIT: Mist deine Antwort übersehen.
Genau deines wäre auch denkbar. Kleines, feines Problem: Versuche mal Buchungen zu erstellen, welche dann keinen Key in den Arbeitsschritten haben weil sie eben nicht auf einer Produktion beruhen. ;)
Ziel hier ist es sicherzustellen, dass das die Im Rezept definierte Zutat auch tatsächlich mit dem Produkt aus ChargeOut übereinstimmt!

Die Stückliste wären hier die Zutaten, das effektiv zugeteilte die Buchungen.