Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

Zwei Fremdschlüssel in einer Tabelle mit selbem Elternschlüssel?

Dieses Thema im Forum "MySQL und MariaDB" wurde erstellt von Rakloedder, 26 November 2015.

  1. Rakloedder

    Rakloedder Benutzer

    Hi :)

    Habe früher mit einer Entwicklungsumgebung namens Clarion gearbeitet, in der man ein sog. dictionary definieren konnte, in der sämtliche Beziehungen zwischen Tabellen und noch einiges mehr bestimmt wurden.

    Unter anderem konnte man dort ein ALIAS für eine Tabelle definieren; dort war es quasi eine virtuelle Kopie einer anderen Tabelle mit eigenem Namen. Bei Relationen wurden die Original-Tabelle und die Alias-Tabelle wie unabhängige Tabellen behandelt. Trotzdem: Wenn man in der Original-Tabelle etwas änderte, betraf diese Änderung auch die Alias-Tabelle und umgekehrt - logisch. Damit war es möglich, eine mehrfache 1:m-Relation zwischen zwei Tabellen zu machen. Beispiel:

    * Eltern-Tabelle mit Flughafen-Namen als Primärschlüssel
    * Kind-Tabelle mit Flugstrecken, bestehend aus Abflug-Flughafen und Ankunft-Flughafen jeweils als Fremdschlüssel.

    Es soll eine zweifache 1:m-Relation zwischen den Tabellen bestehen, so dass bei einer Änderung des Flughafen-Namens in der Eltern-Tabelle die Namen auch in der Kind-Tabelle geändert werden, und zwar ggf. für Abflug- und Ankunft-Flughafen.

    Geht das mit mySQL irgendwie?

    Es ist mir klar, dass man das zum Beispiel mit Triggern erledigen könnte, aber wenn man anfängt, solche Grundaufgaben wie UPDATE oder DELETE mit Triggern zu erledigen, dann könnte man sich die automatische Referentielle Integrität von InnoDB auch gleich sparen...

    Grüße
    Ralph
     
  2. ukulele

    ukulele Datenbank-Guru

    Welche Referentielle Integrität von InnoDB meinst du? Meines wissens nach gibt es die nicht da Foreign Key Constraints in MySQL nicht durchgesetzt werden.

    Du suchst ON UPDATE CASCADE auf deinen Foreign Key Constraints. Damit würde es gehen, ob MySQL das kann weiß ich nicht, ich zweifle daran.

    Alternativ würde ich nicht Flughafen-Namen als PK wählen sondern immer einen künstlichen Schlüssel. Es erleichtert die Sache und man hat nur eine ID mehr die aber für jeden Anwender immer im Hintergrund bleibt.
     
  3. Rakloedder

    Rakloedder Benutzer

    Doch, mit der InnoDB engine geht das.

    InnoDB kennt constraints der beschriebenen Art und setzt sie um

    Ändert aber am Problem nix. Man kann ohne eine virtuelle Kopie der Eltern-Tabelle nicht eine Eltern-Tabelle zwei mal mit einer Kind-Tabelle verknüpfen.

    Die Frage war ja, ob es in MySQL so etwas wie eine virtuelle Kopie gibt.
     
  4. ukulele

    ukulele Datenbank-Guru

    Also das von dir beschriebene Konstrukt mit einer art Schatten-Tabelle kenne ich so nicht, ich könnte es aber bauen aus Tabellen / Sichten. Das ist aber gar nicht nötig in diesem Fall.

    Das ist nicht korrekt denn das mag unter MySQL nicht gehen, normalerweise ist das kein Problem. Hier mal ein Test mit MSSQL:
    Code:
    CREATE TABLE test_primaer(
       pk UNIQUEIDENTIFIER NOT NULL
       );
    
    CREATE TABLE test_sekundaer(
       pk UNIQUEIDENTIFIER NOT NULL,
       fk1 UNIQUEIDENTIFIER NULL,
       fk2 UNIQUEIDENTIFIER NULL
       );
    
    ALTER TABLE test_primaer ADD CONSTRAINT test_primaer_pk PRIMARY KEY(pk);
    ALTER TABLE test_sekundaer ADD CONSTRAINT test_sekundaer_pk PRIMARY KEY(pk);
    ALTER TABLE test_sekundaer ADD CONSTRAINT test_sekundaer_fk1 FOREIGN KEY(fk1) REFERENCES test_primaer(pk);
    ALTER TABLE test_sekundaer ADD CONSTRAINT test_sekundaer_fk2 FOREIGN KEY(fk2) REFERENCES test_primaer(pk);
    
    INSERT INTO test_primaer(pk) VALUES('CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A');
    
    SELECT * FROM test_primaer;
    --CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A
    
    INSERT INTO test_sekundaer(pk,fk1,fk2) VALUES(newid(),'CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A','CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A');
    
    SELECT * FROM test_sekundaer;
    --A3C02DF6-0517-4513-9694-E92F9C3C526B   CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A   CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A
    
    DELETE FROM test_primaer;
    --Die DELETE-Anweisung steht in Konflikt mit der REFERENCE-Einschränkung 'test_sekundaer_fk1'. Der Konflikt trat in der xxx-Datenbank, Tabelle 'dbo.test_sekundaer', column 'fk1' auf.
    
    UPDATE test_primaer SET pk = newid();
    --Die UPDATE-Anweisung steht in Konflikt mit der REFERENCE-Einschränkung 'test_sekundaer_fk1'. Der Konflikt trat in der combit-Datenbank, Tabelle 'dbo.test_sekundaer', column 'fk1' auf.
    
    Es werden definitiv zwei Fremdschlüssel von der sekundaer-Tabelle auf die primaer-Tabelle gesetzt. Der Test zeigt auch, das die Referentielle Integrität funktioniert. Ich bin mir sicher das MySQL auch mit InnoDB in der Vergangenheit zwar den Schlüssel erstellt hat, ihn dann aber beim gezeigten DELETE selbst verletzt und den DELETE ausgeführt hat.

    Hier noch das, was du suchst:
    Code:
    ALTER TABLE test_sekundaer DROP CONSTRAINT test_sekundaer_fk1;
    ALTER TABLE test_sekundaer DROP CONSTRAINT test_sekundaer_fk2;
    ALTER TABLE test_sekundaer ADD CONSTRAINT test_sekundaer_fk1 FOREIGN KEY(fk1) REFERENCES test_primaer(pk) ON UPDATE CASCADE;
    
    UPDATE test_primaer SET pk = newid();
    --UPDATE test_primaer SET pk = newid();
    
    SELECT * FROM test_primaer;
    --AB3F6C3F-A968-49E9-AC5D-11EE68BC7272
    SELECT * FROM test_sekundaer;
    --A3C02DF6-0517-4513-9694-E92F9C3C526B    AB3F6C3F-A968-49E9-AC5D-11EE68BC7272    CE5C3EAF-4B5B-4578-BCAE-60CFD15F552A
    CASCADE funktioniert, allerdings nicht mit zwei Fremdschlüsseln, zumindest hab ich es auf die Schnelle nicht hinbekommen. Ich finde CASCADE aber problematisch, ich würde wirklich einen rein künstlichen PK führen, das ist meiner Meinung nach deutlich eleganter als einen PK auf einen Namen wie in deinem Beispiel. Wäre der Name kein PK ließe er sich einfach ändern und würde immer richtig gejoint werden.
     
  5. Rakloedder

    Rakloedder Benutzer

    Hmmm. Also ich hab's jetzt mal mit dem Designer in phpMyAdmin versucht. Mag das Ding nicht, aber es hat tatsächlich dort funktioniert, was per SQL zu Fehlermeldungen geführt hat... Teste noch, ob das alles so funzt.
     
  6. Rakloedder

    Rakloedder Benutzer

    Alles einwandfrei. Alle constraints werden durchgesetzt, keine Probleme.
     
  7. ukulele

    ukulele Datenbank-Guru

    Gut, klappt es auch mit zwei Foreign Keys auf die Eltern-Tabelle aus der Kind-Tabelle? Wie gesagt unter MSSQL geht es, unter MySQL weiß ich nicht.
     
  8. akretschmer

    akretschmer Datenbank-Guru

    Sicher?

    Probier mal aus, was da da in MySQL passiert:

    Code:
    test=*# create table rakloedder(i int check(i < 10));
    CREATE TABLE
    test=*# insert into rakloedder values (12);
    ERROR:  new row for relation "rakloedder" violates check constraint "rakloedder_i_check"
    DETAIL:  Failing row contains (12).
    test=*#
    
    Immer noch "alles einwandfrei"?
     
  9. Rakloedder

    Rakloedder Benutzer

    Also bei mir funktioniert es so, wie ich es erwarte. Mehr kann ich nicht sagen. Bin auch nicht sicher, was obiger Code-Schnitzel nun zeigen soll?
     
  10. Rakloedder

    Rakloedder Benutzer

    Funktioniert auch. Hatte erst Zweifel, weil ich lokal MariaDB laufen habe. Klappt aber auch auf dem Entfernten mit MySQL.
     
  11. akretschmer

    akretschmer Datenbank-Guru

    Das MySQL keine Check-Constraints beachtet.
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden