Forum: PC-Programmierung SQL Datenbank n:1 Beziehung mit n!=0


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Gerd (Gast)


Lesenswert?

Hallo zusammen,

ich habe in einer Datenbank (postgresql) 2 Tabellen in der Form:
Tabelle 1: ID(serial), key(int FK)
Tabelle 2: key(int PK), data(int)
Zwischen diesen Tabellen möchte ich eine n:1-Beziehung, wobei n nicht 
gleich 0 sein darf. Mit anderen Worten: In Tabelle 2 darf keine Zeile 
existieren, deren key nicht in Tabelle 1 ist.

Und da stehe ich irgendwie auf dem Schlauch. Ein Lösungsansatz von mir, 
dies nicht auf Datenbankebene sondern auf Applikationsebene zu lösen, in 
dem ich programmgesteuert alle Einträge überprüfe. Dies würde 
funktionieren, ist aber in meinen Augen nicht sauber gelöst.

Auf der anderen Seite, selbst wenn ich diese Abhängigkeit hinkriege 
hätte ich keine Ahnung, wie ich neue Datensätze anlegen kann, da beide 
Tabellen voneinander abhängig sind, müssten die beiden Datensätze 
gleichzeitig angelegt werden (aber wahrscheinlich mit SQL irgendwie 
machbar).

Jemand eine Idee?

Gerd

der Hintergrund:
In der Datenbank ist unter anderem ein Abbild eines Verzeichnisses 
gesichert. In Tabelle A liegen die Dateinamen, in Tabelle B die iNodes. 
Da durch Links, mehrere Dateien die selbe Inode haben können aber eine 
Inode zwingend mindestens einen Dateinamen braucht ergibt sich das 
Problem.

von (prx) A. K. (prx)


Lesenswert?

Henne-Ei Problem? Um in Tab1 was eintragen zu können muss der Key schon 
in Tab2 drin sein. Das genau willst du aber verbieten.

von (prx) A. K. (prx)


Lesenswert?

Kannst versuchen, umgekehrt vorzugehen. Also z.B. an Löschaktionen in 
Tab1 einen Trigger dranhängen, der ggf. den Eintrag in Tab2 löscht.

von Oliver R. (Gast)


Lesenswert?

Es gibt in PostgreSQL die Möglichkeit innerhalb einer Transaktion die 
Constraint-Überprüfungen zu deaktivieren:

http://www.postgresql.org/docs/9.1/static/sql-set-constraints.html

Ich persönlich würde zwar versuchen es anders zu lösen, vielleicht ist 
es aber für dich nützlich.

von (prx) A. K. (prx)


Lesenswert?

Oliver R. schrieb:
> Es gibt in PostgreSQL die Möglichkeit innerhalb einer Transaktion die
> Constraint-Überprüfungen zu deaktivieren:

Aufgeschoben, aka DEFERRED, würde besser passen.

von Philipp K. (philipp_k59)


Lesenswert?

Vielleicht sowas:

The FOREIGN KEY constraint is used to prevent actions that would destroy 
links between tables.

The FOREIGN KEY constraint also prevents invalid data from being 
inserted into the foreign key column, because it has to be one of the 
values contained in the table it points to.

http://www.w3schools.com/sql/sql_foreignkey.asp

Und noch die Super Erklärung.. Options wäre interessant in diesem Link:
https://de.wikibooks.org/wiki/Einf%C3%BChrung_in_SQL:_Fremdschl%C3%BCssel-Beziehungen

: Bearbeitet durch User
von Gerd (Gast)


Lesenswert?

Hm,

vielen Dank soweit. Ich beginne zu glauben, dass mein Vorhaben nicht 
umsetzbar ist.
Der Ansatz das ganze über eine Transaction zu erledigen in der ich die 
CONSTRAINTS auf DEFERED setze um die Überprüfung erst am Ende der 
Transaktion durchzuführen klingt gut. Allerdings scheitere ich schon 
einen Schritt vorher.
Ich habe nun versucht die beiden Tabellen zu erstellen, was nicht 
möglich ist. psql lässt die Erstellung von TabB nicht zu. Begründung: 
Der Wert von Key in TabA ist nicht eindeutig. Diese Eindeutigkeit kann 
es jedoch nicht geben, denn es sollen ja eben mehrere Einträge in TabA 
auf B verweisen. Allerdings steht dies im Gegensatz zur Funktionsweise 
von Fremdschlüsseln. Das ganze führt dazu, dass ich den gesammten 
Entwurf wohl ändern muss.

Aktuell sehe ich nur eine andere Möglichkeit:

Einfügen einer weiteren Tabelle zur Verknüpfung. Eigenetlich für m:n 
Beziehungen
TabA 1: ID(int PK) name(text)
TabB 2: ID(int PK) inode(int)
TabC 3: id_a(int FK UNIQUE), id_b(int FK)
Dazu müsste ich jetzt der Datenbank sagen, dass es für jeden Eintrag in 
A mindest einen Eintrag in C geben muss. k.A. ob, dies möglich (und 
sinnvoll) ist.

Zwar finde ich noch andere Möglichkeiten, jedoch verstossen diese gegen 
die Normalisierung. Darüber könnte man hinwegsehen, aber dann habe ich 
keine Vorteile mehr gegenüber meiner ursprünglichen Lösung. Die 
Konsistenz müsste ich dann immer wieder händisch prüfen.

tldr:
Das Einfügen ist aktuell nicht mehr mein Problem. Ich müsste erst einmal 
die dafür notwendigen Tabellen erstellen, und da scheitere ich schon. 
Jemand noch eine Idee für ein vernünftiges Design?

Gerd

von Philipp K. (philipp_k59)


Lesenswert?


von Gerd (Gast)


Lesenswert?

Philipp K. schrieb:
> http://sqlfiddle.com/#!15/274f0/15

Danke. Eine Lösung scheint es leider nicht für mich zu sein. Dort 
beschrieben ist eine 1:n Beziehung. In der Tabelle cities kann eine 
Stadt existieren, ohne dass in der Tabelle weather eine zugehöriger 
Datensatz existiert. Dies ist genau der Umstand den ich vermeiden 
möchte. So wie ich es sehe, würde ein Löschen eines Datensatzes in 
cities auch die zugehörigen Datensätze in weather löschen. Nur andersrum 
halt nicht.

von der, der auch mal zockt (Gast)


Lesenswert?

Dann definiere doch ein DefaultWeather in cities. Darauf noch ein 
constraint und das DefaultWeather mandatory. Dann hättest du doch deinen 
Wunsch oder nicht?

von Philipp K. (philipp_k59)


Lesenswert?

Ja moment mal aber Du bist doch der Auslöser einer City.. wenn Du nie 
eine City schreibst dann gibt es diese auch nicht und damit können auch 
keine Weather dazu angelegt werden.

In postgre musst Du letzendlich für komplizierte verschachtelungen 
Transactions benutzen sonst kannste auch gleich mysql nehmen, mit dem 
schon vorgeschlagenem Deferred und foreign Key solltest Du das dann 
hinbekommen.

Da gibts schon einige Lösungen auf Deine Frage bei Stackoverflow.. ich 
benutze nur mysql.

von Konrad S. (maybee)


Lesenswert?

Gerd schrieb:
> aber eine
> Inode zwingend mindestens einen Dateinamen braucht ergibt sich das
> Problem.

Für unixoide Dateisysteme ist das nicht richtig. Der Inode existiert, 
solange er referenziert wird. Ein Prozess kann einen Inode referenzieren 
und dann dürfen alle Verzeichniseinträge gelöscht werden. Dafür hat der 
Inode einen Referenzzähler. Geht dieser auf Null, so wird der Inode 
gelöscht.

Edit:
Also Trigger auf den Referenzzähler.

: Bearbeitet durch User
von Gerd (Gast)


Lesenswert?

der, der auch mal zockt schrieb:
> Dann definiere doch ein DefaultWeather in cities. Darauf noch ein
> constraint und das DefaultWeather mandatory. Dann hättest du doch deinen
> Wunsch oder nicht?
Aber auf welches Wetter sollte sich das Defaultwetter beziehen?
Ich denke das Problem ist, dass das Ausgangsszenario mit dem 
City/Weather Beispiel nicht vergleichbar ist. Denn während eine inode 
mehreren Dateien zugeordnet werden kann, macht es wenig Sinn dass ein 
Wetter mehreren Städten zugeordnet ist. Hier fehlt eine Eindeutigkeit.

Philipp K. schrieb:
> Ja moment mal aber Du bist doch der Auslöser einer City.. wenn Du nie
> eine City schreibst dann gibt es diese auch nicht und damit können auch
> keine Weather dazu angelegt werden.
Mir geht es nicht so sehr um das anlegen, sondern um das versehentliche 
löschen von Städten, für die noch Wetterdaten existieren, wobei diese 
Wetterdaten eventuell noch von anderen Städten referenziert werden, und 
dann nicht gelöscht werden dürfen.

von Gerd (Gast)


Lesenswert?

Konrad S. schrieb:
> Für unixoide Dateisysteme ist das nicht richtig. Der Inode existiert,
> solange er referenziert wird. Ein Prozess kann einen Inode referenzieren
> und dann dürfen alle Verzeichniseinträge gelöscht werden. Dafür hat der
> Inode einen Referenzzähler. Geht dieser auf Null, so wird der Inode
> gelöscht.
war mir nicht klar, allerdings kann ich damit leben. Dass eine inode 
noch von einem Prozess referenziert wird ist ok. Ich möchte in diesem 
Fall keine 1:1 Kopie der iNodes der Partition haben, sondern nur den 
Teil der aus einem bestimmten Verzeichnis referenziert wird. Fehlen 
diese im Verzeichnisse werden sie aus der Datenbank gelöscht.

von Philipp K. (philipp_k59)


Lesenswert?

Oder man macht das ganz anders und Googelt mal nach "Postgre" oder "SQL" 
Tree/Node/Hierarchy.

Vielleicht wäre so etwas einfach komfortabler:

http://www.postgresql.org/docs/9.1/static/ltree.html

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.