Laden...

Doppelte Beziehung zwischen zwei Tabellen

Erstellt von Jörg vor 14 Jahren Letzter Beitrag vor 13 Jahren 13.154 Views
J
Jörg Themenstarter:in
152 Beiträge seit 2009
vor 14 Jahren
Doppelte Beziehung zwischen zwei Tabellen

verwendetes Datenbanksystem: SQL Server 2008 Express

Hallo, ich habe in einer Sub-Tabelle zwei Spalten die auf den PrimKey der Master-Tabelle verweisen:

TableMaster
Master ID (PK)
(weitere Spalten...)

TableSub
Sub ID (PK)
Master ID (Relation zur Master-Tabelle)
Zus Master ID (Eine zweite Relation zur Master-Tabelle)

Die erste Relation (Master ID <-> Master ID) lässt sich problemlos einrichten.
Sobald ich versuche die zweite Relation (Master ID <-> Zus Master ID) einzurichten, erhalte ich folgende Fehlermeldung:
"Die referenzielle Beziehung führt zu einem nicht zulässigen zyklischen Verweis"

Was kann ich dagegen tun??
Im Prinzip möchte ich ja nur folgendes durch die Relationen erreichen:
Wird ein Eintrag aus der TableMaster gelöscht, sollen aus der TableSub alle Einträge gelöscht werden, die in Master ID oder Zus Master ID die gelöschte Master ID der TableMaster stehen haben.

Gruß Jörg

1.552 Beiträge seit 2010
vor 14 Jahren

Hallo Jörg,

ich kann dein Problem nicht ganz nachvollziehen?
Wieso brauchst du in deiner anderen Tabelle 2x einen ForeignKey auf die MasterTabelle?
Es reicht ja schon ein ForeignKey aus.

Gruß,
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

J
Jörg Themenstarter:in
152 Beiträge seit 2009
vor 14 Jahren

Hallo,

bisher hat mir ein ForeignKey auf die Master-Tabelle auch immer ausgereicht. 😁

Nur im vorliegenden Fall soll halt zusätzlich ein zweiter Key auf die Master-Tabelle verweisen.

Sozusagen:
Eintrag "567 Sub" gehört zu Eintrag "123 Master", verweist aber zusätzlich auf Eintrag "444 Master".

Wenn nun "123 Master" oder "444 Master" gelöscht wird, soll halt auch der Sub verschwinden.

Gruß Jörg

C
112 Beiträge seit 2009
vor 14 Jahren

Moin,

sowas geht nicht. Das würde ja beispielsweise bedeuten, dass es zu einem Kunden zwei Rechnungen gibt (normal) aber auch zu mindestens einer dieser Rechnungen zwei Kunden, und das macht ja nun gar keinen Sinn und wird zu Recht vom DBMS zurückgewiesen. Es lassen sich nur 1:n Beziehungen in einem relationalen DBMS darstellen.
In Deinem Fall müsstest Du entweder in Deiner sub-Tabelle zwei identische Einträge haben, die sich nur in der Referenz auf die Master-Tabelle unterscheiden -> schlechtes Datenbankdesign
oder eine Interselektionstabelle, die den Einträgen aus der Mastertabelle jeweils einen Eintrag aus der Sub-Tabelle zuordnet,
etwa so:


Master   Interselektionstabelle        Sub
id           idMaster     idSub              id
1             1              4                    1
2             1              3                    2
3             3              1                    3 
4             4              2                    4

Grüße

Christian

34 Beiträge seit 2009
vor 14 Jahren

Hallo zusammen,

das Problem von Jörg ist aus meiner Sicht garnicht so unüblich. Angenommen man hat eine Tabelle in welcher Personendaten stehen. In einer weitern Tabelle stehen diese Personen in Beziehung zueinander Person-A kennt Person-B. Somit ist ein FK von Person-A.ID und ein FK von Person-B sinnvoll.


Tabelle PERSON          Tabelle RELATION
ID | NAME               ID | RELATION | PERSONAID | PERSONBID
----------------        -------------------------------------
1  | Jörg               88 | kennt    |         1 |        2
2  | xxMUROxx           89 | kennt    |         2 |        3
3  | chriscolm

Ich denke Jörg möchte ein "delete cascade" machen. Da ist die Benutzung von "cascade" nicht so mag, weil ich immer gern wissen möchte was alles gelöscht wird, würde ich dir folgendes empfehlen (auf mein Beispiel bezogen).


delete from RELATION where PERSONAID = @value or PERSONBID = @value

Das löst zwar nicht das Probem des 2ten FK's aber es würde funktionieren.
Ich kenne SQL Server 2008 Express nicht, aber ich glaube "richtige" 😉 Datenbanken können das.

MFG

ashinger

1.552 Beiträge seit 2010
vor 14 Jahren

Soeben habe ich es beim PC zuhause probiert die Tabellen die Jörg anfänglich beschreibt in Access probiert. Folgendes CREATE Statements funktioniert dort ohne Probleme:


CREATE TABLE tableA(id integer PRIMARY KEY, name varchar(5));

CREATE TABLE tableB(pk varchar(5) PRIMARY KEY , id1 integer REFERENCES tableA(id), id2 integer  REFERENCES tableA(id));

Ob es unter SQL Server Express funktioniert kann ich dir leider nicht sagen da ich zuhause keinen SQL Server installiert habe.

Gruß,
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

J
Jörg Themenstarter:in
152 Beiträge seit 2009
vor 14 Jahren

Hallo,

anscheinend sperrt sich der SQL-Server gegen die doppelte 'Cascade'-Löschregel.
Wenn ich als Löschregel 'No Action' angebe, kann ich mit beiden Fremdschlüsseltabellenspalten eine Beziehung zur Primärschlüsseltabellenspalte aufbauen.

Sobald ich versuche beide Beziehungen mit Löschregel 'Cascade' zu erstellen, kommt bei der zweiten Beziehung die Fehlermeldung "Die referenzielle Beziehung führt zu einem nicht zulässigen zyklischen Verweis".

Gruß
Jörg

R
14 Beiträge seit 2007
vor 13 Jahren

Hallo, ich habe denke ich dasselbe Problem. Zur Veranschaulichung und Verständnis habe ich mal eine Beispieldatenbank erstellt (Anhang).
Das Design liegt zugegeben etwas ausserhalb der üblichen Schemata, ist jedoch meiner Ansicht nach recht nah am (Performanz)optimum. Würde man die beiden Rollen der Person über eine Extratabelle herstellen (normalisiert), würde ein recht großer Informationsoverhead entstehen. Aus der 2:n würde eine n:m-Beziehung werden, was zusätzlich zum Informationsoverhead auch noch Performanznachteile mit sich brächte. Vor Allem, da in meinem konkreten Fall auf die Personen nur von Seiten des Autos zugegriffen wird. (also entweder get alle personen oder get auto mit personen)

Normale Fremdschlüsselbeziehungen funktionieren hierbei (2:n) auch soweit problemlos, sobald jedoch SET NULL oder CASCADE Einschränkungen hinzukommen beisst sich die Katze in den Schwanz (selbe Fehlermeldung wie im ersten posting). Normalerweise hätte ich das vemutlich schon über Trigger gelöst, allerdings erlaubt mssql compact diese nicht X( .

Wäre super wenn jemand ein Pattern für dieses Problem wüsste, oder eine Idee hätte wie dies zu lösen wäre? =)

2.760 Beiträge seit 2006
vor 13 Jahren

Dann nimm doch eine Stored Procedure.

R
14 Beiträge seit 2007
vor 13 Jahren

Ergänzung: Im Anhang wäre die normalisierte Variante, über die ich mal vermuten würde das das Kaskadieren funktioniert, da immer nur eine Tabelle mit einer oder mehreren Tabelle verknüpft ist. Möglicherweise bin ich auch gerade völlig aufm Holzweg, aber besonders schön find ich die Variante nich.

(PS: die doppelpfeile stelle 1:1 verknüpfungen dar, ka wie das in Visio-Syntax auszudrücken ist, damit man das auch visuell erkennt)

R
14 Beiträge seit 2007
vor 13 Jahren

Dann müsste ich aber die stored procedure selber ab und zu aufrufen, um die cascades/set nulls durchzuführen, oder?

2.760 Beiträge seit 2006
vor 13 Jahren

Jup, so ist es. Sauberer wäre es IMHO ohnehin eine Schicht aus Stored Procedures für den Datenzugriff dazwischenzuziehen.
Selbst wenn du deine Tabellen irgendwann mal umwirfst und dich für den anderen Ansatz entscheidest bleibt im besten Fall deine Client-Anwendung davon unberührt.

R
14 Beiträge seit 2007
vor 13 Jahren

Hm, da auf der Datenbank eine Entity Framework Persistenzschicht aufsetzt wäre das mit ausschließlich stored Procedures wohl irgendwie dran vorbei gearbeitet. Auch die stored procedure zum kaskadieren der Änderungen wäre vermutlich recht langsam, oder man müsste es in den EF-Klassen unterbringen damit es nach dem Ändern ausgeführt wird, was beides nicht besonders sauber wäre, vor Allem wenn man noch andere Datenbanken anbinden will (ausser mssql ce).
Bei der normalisierten Variante frage ich mich auch gerade, ob das EF das überhaupt erkennt. n:m Beziehung sind damit zwar auflösbar, aber das ist vermutlich schon recht speziell X(
Naja, mit der stored procedure mit Aufruf aus der EF-Klasse ist auf jeden Fall bisher die beste Lösung.

R
14 Beiträge seit 2007
vor 13 Jahren

Also ich hab grad zum Einen festgestellt, das mssql compact keine stored procedures unterstützt. Zum Anderen bekomm ich die DB ja nur mit NO ACTION implementiert, was quasi bedeutet, das ich überhaupt keine Personen löschen kann. Das wär natürlich Murks. Dann werd ich wohl die komplizierte Variante probieren müssen. Frage ist natürlich auch, wie bekomm ich das dann schön in die EF-Klassen übersetzt 🤔 Ich werd natürlich hier posten, ob und wie es funktioniert.

Nunja, für gute Ideen bin ich aber derweil immernoch zu Haben 😁

M
17 Beiträge seit 2010
vor 13 Jahren

Wie ja schon festgestellt, macht es wenig Sinn, auf DB Seite noch eine Stored Procedures Schicht zwischen zu ziehen. Damit macht man sich abhängig von einer DB, da alle ihre eigene Skriptsprache verwenden, bzw. manche DBs dies gar nicht unterstützen. Die korrekte Variante zur Problemlösung wurde auch schon genannt, nämlich die Normalisierung des Schemas, was einerseits saubereres DB-Design ist und einem zweitens mehr Flexibilität bei Abfragen gibt.

R
14 Beiträge seit 2007
vor 13 Jahren

Hi, danke für den Hinweis. Leider lässt sich damit aber keine (quasi) 4:n Beziehung für das entity framework verständlich auchdrücken. Daher hab ich mich dafür entschieden 4 n:m Beziehungen zu machen, zumindest ist es auch nicht völlig abwegig, das ein Auto mehrere Fahrer haben kann. Die UI ist dann dahingehend optimiert, das es einfacher ist einen Fahrer hinzuzufügen, mehrere sind dan natürlich auch möglich.

Leider bin ich schon wieder auf ein neues Problem in dem Zusammenhang gestoßen, aber das poste ich mal in einem neuen Thema, wär sonst off-topic.

Vielen Dank nochmal an alle für die Hinweise 🙂