Automatisches Erzeugen eines PK bei Insert eines FK

Tom.S

Fleissiger Benutzer
Beiträge
62
Hallo,
mal wieder eine Frage, bei der ich die Antwort zu wissen glaube, aber sichergehen möchte:
Ich habe Tabellen, beispielsweise
Porsche | Audi | VW...
und eine "abstrakte" Tabelle "Auto". Jeder Datensatz zu einem Wagen, den ich in eine der Markentabellen eintrage, soll automatisch zu einem Eintrag in der Auto-Tabelle führen, auf den dann ein Fremdschlüssel in der Markentabelle zeigt. In etwa so:

Auto
| ID |

Porsche
| ID | AUTO_ID_FK | Typ ...

Der beste Weg, der mir einfällt, ist die Realisierung über einen Trigger in der Markentabelle.
Liege ich richtig, dass man es mit einem Trigger löst oder gibt es bei PostgreSQL noch einen weiteren Weg, um so eine 1-zu-1-Verknüpfung sicherzustellen?
 
Werbung:
Hallo,
mal wieder eine Frage, bei der ich die Antwort zu wissen glaube, aber sichergehen möchte:
Ich habe Tabellen, beispielsweise
Porsche | Audi | VW...
und eine "abstrakte" Tabelle "Auto". Jeder Datensatz zu einem Wagen, den ich in eine der Markentabellen eintrage, soll automatisch zu einem Eintrag in der Auto-Tabelle führen, auf den dann ein Fremdschlüssel in der Markentabelle zeigt. In etwa so:

Auto
| ID |

Porsche
| ID | AUTO_ID_FK | Typ ...

Der beste Weg, der mir einfällt, ist die Realisierung über einen Trigger in der Markentabelle.
Liege ich richtig, dass man es mit einem Trigger löst oder gibt es bei PostgreSQL noch einen weiteren Weg, um so eine 1-zu-1-Verknüpfung sicherzustellen?

Falls ich Dich richtig verstehe, liegst Du richtig. Aber ich versteh noch nicht das Problem, was Du damit lösen willst. Das klingt etwas wie Partitionierung, aber irgendwie falsch herum. Deine Auto-Tabelle wäre ja dann die Master-Tabelle, aber die bleibt gewöhnlich leer.
 
@akretschmer Das Problem, das ich lösen möchte: Beispielsweise möchte ich Mitarbeiter und ihre Firmenwägen verknüpfen. Dafür habe ich dann eine Koppelungstabelle "mitarbeiter_zu_firmenauto", in der ein Mitarbeiter-FK und ein Auto-FK drin sind. Hätte ich jetzt nicht die Supertabelle Auto müsste ich zig Tabellen "mitarbeiter_zu_firmenauto-vw", "mitarbeiter_zu_firmenauto_porsche" etc. anlegen. So zumindest meine Vorstellung. Da ich in Sachen PostgreSQL ein Newbie bin, höre ich gerne bessere Ideen.
Mit Partitionierung hat das nichts zu tun, eher mit Inheritance, aber damit habe ich noch nicht gearbeitet und kann nicht beurteilen, ob es sich damit besser lösen ließe.

@Distrilec Ein FK mit Unique-Constraint ist natürlich notwendig, der erzeugt mir aber nicht automatisch den Eintrag in die Autotabelle.
 
Ich gehe das jetzt einmal logisch durch:
1. Jemand trägt in deine Tabelle "mitarbeiter_zu_firmenauto" eine neue Verknüpfung Personalnummer 123 zu Auto xyz ein.
2. Der Foreign Key "merkt" das es das Auto xyz noch nicht gibt.
3. Hier willst du dann automatisch in die Mastertabelle "firmenautos" das Auto xyz anlegen. Richtig?
Der bloße Gedanke daran lässt mich würgen... Aber ok...

Das wäre evtl. über einen Before Insert-Trigger möglich...
Dann könntest du dir aber den FK sparen... und müsstest das Vorhandensein während dem Trigger-Durchlauf prüfen...

Etwas worauf ich dich dann aber direkt hinweisen möchte:
- Wo nimmst du die Stammdaten für das Auto her? Oder willst du nur die PK-Spalten befüllen und den Rest NULL lassen?
- Was ist wenn sich jemand nur vertippt? Dann hast du ein Auto das garnicht existiert...
- Du widersprichst damit sämtlichen Logiken/Konventionen/Ideen
- Du widersprichst damit in jeder Art und Weise dem Sinn hinter einer relationalen Datenbank...

Einen produktiven Nutzen für eine echte Firma sehe ich da leider auch nicht... Also lass es lieber bleiben...
Wenn du das wirklich durchziehst, sage ich dazu nur eins... Selbst Excel hat mehr mit Relation zu tun als deine Listen (Ich will es schon garnichtmehr Modell nennen)
 
Mit Partitionierung hat das nichts zu tun, eher mit Inheritance, aber damit habe ich noch nicht gearbeitet und kann nicht beurteilen, ob es sich damit besser lösen ließe.

Inheritance und Foreign-Key-Constraints funktionieren nicht so, wie man sich das erhofft. Ich würde das hier nicht nehmen. Wenn Du je Auto unterschiedliche Merkmale noch speichern willst würde ich eher zu HSTORE (Key-Value) oder JSON(B) raten.
 
Wo nimmst du die Stammdaten für das Auto her?

er will, denke ich, sowas machen:

Code:
test=*# create table auto(id int primary key, kennzeichen text);
CREATE TABLE
test=*# create table auto_vw (extra_vw text) inherits (auto);
CREATE TABLE
test=*# create table auto_opel (extra_opel text) inherits (auto);
CREATE TABLE
test=*# create table mitarbeiter (id int primary key, name text);
CREATE TABLE
test=*# create table mitarbeiter_auto (mitarbeiter int references mitarbeiter, auto int references auto);
CREATE TABLE
test=*# insert into auto_vw values (1, 'dd 0815', 'extra gimmick vw');
INSERT 0 1
test=*# insert into auto_opel values (2, 'dd 4711', 'extra gimmick opel');
INSERT 0 1
test=*# insert into mitarbeiter values (1, 'vw-freak');
INSERT 0 1
test=*# insert into mitarbeiter values (2, 'opel-freak');
INSERT 0 1
test=*# insert into mitarbeiter_auto values (1,1);
ERROR:  insert or update on table "mitarbeiter_auto" violates foreign key constraint "mitarbeiter_auto_auto_fkey"
DETAIL:  Key (auto)=(1) is not present in table "auto".
STATEMENT:  insert into mitarbeiter_auto values (1,1);
ERROR:  insert or update on table "mitarbeiter_auto" violates foreign key constraint "mitarbeiter_auto_auto_fkey"
DETAIL:  Key (auto)=(1) is not present in table "auto".

Das Problem ist halt, daß die Tabelle auto an sich leer ist, die Daten stehen nur in den Kind-Tabellen. Leider kann ich so auch nicht einen FK auf die auto - Tabelle legen.
 
Ich gehe das jetzt einmal logisch durch:
1. Jemand trägt in deine Tabelle "mitarbeiter_zu_firmenauto" eine neue Verknüpfung Personalnummer 123 zu Auto xyz ein.
2. Der Foreign Key "merkt" das es das Auto xyz noch nicht gibt.
3. Hier willst du dann automatisch in die Mastertabelle "firmenautos" das Auto xyz anlegen. Richtig?
Nicht ganz: Die Firmenautos werden alle beim Kauf angelegt. Die Verknüpfung zu der Mitarbeiter-Tabelle war nur als Beispiel für das Problem gedacht. Meine Idee war es, dass wenn ein neuer Firmenwagen angelegt wird, der markenspezifische Attribute hat, automatisch per Before-Insert-Trigger ein PK in der Auto-Tabelle eingefügt wird und anschließend dieser PK als FK in der firmenwagen-porsche- Tabelle zusammen mit den anderen markenspezifischen Attributen eingetragen wird.

Das wäre evtl. über einen Before Insert-Trigger möglich...
Dann könntest du dir aber den FK sparen... und müsstest das Vorhandensein während dem Trigger-Durchlauf prüfen...
Aber der FK ist doch dennoch wichtig, damit bei Updates etc. alles konsistent bleibt.

Der bloße Gedanke daran lässt mich würgen... Aber ok...
...
Etwas worauf ich dich dann aber direkt hinweisen möchte:
- Wo nimmst du die Stammdaten für das Auto her? Oder willst du nur die PK-Spalten befüllen und den Rest NULL lassen?
- Was ist wenn sich jemand nur vertippt? Dann hast du ein Auto das garnicht existiert...
- Du widersprichst damit sämtlichen Logiken/Konventionen/Ideen
- Du widersprichst damit in jeder Art und Weise dem Sinn hinter einer relationalen Datenbank...

Einen produktiven Nutzen für eine echte Firma sehe ich da leider auch nicht... Also lass es lieber bleiben...
Wenn du das wirklich durchziehst, sage ich dazu nur eins... Selbst Excel hat mehr mit Relation zu tun als deine Listen (Ich will es schon garnichtmehr Modell nennen)
So ganz verstehe ich nicht, warum Du das für solch ein Gewürge hälst. Wie würdest Du denn das Problem lösen, wenn Du sagen wir 100 analoge Tabellen hast und sagen wir 10 andere Tabellen, die per FK mit jeder dieser Tabellen verbunden werden sollen? Erstellst Du dann 1000 Koppelungstabellen? Da finde ich die Lösung einer Supertabelle, die per FK mit den Subtabellen verbunden wird, relativ elegant. Und wenn man diese Koppelung per Trigger so fest macht, dass es nicht mehr durch das Clientprogramm aufgebrochen werden kann, finde ich das auch elegant.
Aber wenn mein Ansatz so fatal ist: Wie würdet Ihr das Problem lösen 100 gleichartige Tabellen mit 10 anderen zu verbinden? Mir fällt da keine evidentere Lösung ein, aber vielleicht übersehe ich etwas gravierendes.
 
Ok... Jetzt habe ich auch verstanden was du willst... Bleibt aber leider trotzdem ein Gewürge...
Warum ich das für ein Gewürge halte ist ganz einfach:
Ein gutes ERM wird durch zwei Dinge beschrieben - Integrität und Skalierung...
- Integrität schaffst du über Trigger... Kurz und knapp: Nur weil es möglich ist, heißt es nicht das Sie so auch benutzt werden sollen... Das sollten Sie auf keinen Fall...
- Skalierung... Naja... Du hast keine... Sollte es eine neue Automarke geben bist du gezwungen eine neue Tabelle anzulegen, deine Trigger zu überarbeiten, neue Constraints anzulegen...

Solltest du das wirklich so wollen... Ich kann dir wohl eine Excel-Arbeitsmappe schreiben mit ein bisschen VBA-Code die genau das gleiche kann :)
Du musst keinen Server hosten bzw. für unnötige Lizenzen zahlen und das Ergebnis bleibt gleich...

Da ich das ganze nicht wirklich gut erklären kann, hier mal eben runtergeschrieben (Oracle-Syntax - es sollte trotzdem lesbar sein :) ):
Code:
Create Table person_tab
(
person_id Varchar2(20)

,Constraint person_tab_pk Primary Key (person_id)
);

Create Table attribut_tab
(
attribut_id Varchar2(20)
,bezeichnung Varchar2(200)
,datentyp Varchar2(1) -- A für alphanumerischen Wert / N für numerischen Wert

,Constraint attribut_tab_pk Primary Key (attribut_id)
);

Create Table attribut_schema_tab
(
schema_id Varchar2(20)
,attribut Varchar2(20)

,Constraint attribut_schema_tab_pk Primary key (schema_id, attribut)
,Constraint attribut_schema_tab_fk_01 Foreign Key (attribut) References attribut_tab(attribut_id)
);

Create Table automarken_tab
(
automarken_id Varchar2(20)
,beschreibung Varchar2(200)
,attribut_schema Varchar2(20)

,Constraint automarken_tab_pk Primary Key (automarken_id)
,Constraint automarken_tab_fk_01 Foreign Key (attribut_schema) References attribut_schema_tab(schema_id)
);

Create Table autos_tab
(
auto_id Varchar2(20)
,auto_bezeichnung Varchar2(20)
,besitzer Varchar2(20) -- Ein Auto kann ja immer nur einen Besitzer haben, deswegen kann man das hier so anlegen...
,automarke Varchar2(20)

,Constraint autos_tab_pk Primary Key (auto_id)
,Constraint autos_tab_fk_01 Foreign Key (besitzer) References person_tab(person_id)
,Constraint autos_tab_fk_02 Foreign Key (automarke) References automarken_tab (automarken_id)
);

Create Table auto_attribute_tab
(
auto_id Varchar2(20)
,attribut Varchar2(20)
,wert_alphanum Varchar2(4000)
,wert_num Number

,Constraint auto_attribute_tab_pk Primary Key (auto_id, attribut)
,Constraint auto_attribute_tab_fk_01 Foreign Key (auto_id) References autos_tab(auto_id)
,Constraint auto_attribute_tab_fk_02 Foreign Key (attribut) References attribut_tab(attribut_id)
);
Wenn ich jetzt nichts falsch gemacht habe, kannst du dir im Client eine Tabelle der Attribute für das Schema der Automarke deines neuen Autos anzeigen lassen.
Da du nur diese Anzeigen lässt ist Integrität sichergestellt und du kannst die eingetragenen Werte in die Tabelle auto_attribute_tab schreiben...
(Nicht über die Tabellennamen wundern... Da bin ich immer furchtbar kreativ...)
(Eigentlich sollte das ganze englische Notation haben... Habe das ganze aber nur schnell runter geschrieben... :) )
(Das ganze ist definitiv Verbesserungswürdig... Ich habe da jetzt nicht groß drüber nachgedacht)
 
Ok, jetzt verstehe ich endlich, wo Eure Verständnisprobleme herrühren: Die Sub-Tabellen (porsche, vw,...), sprich die Attribute der Autos, sind natürlich nicht homogen. Sonst könnte ich mir das ganze tatsächlich sparen. Das heißt, ich kann die Attribute der einzelnen Automarken eben nicht in einer Tabelle zusammenfassen (oder es wäre eine riesige mit lauter NULL-Feldern), sondern habe viele Tabellen unterschiedlicher Ausprägung.
Aber all diese heterogenen Tabellen sind Autos. In anderen Tabellen soll auf jeden beliebigen Auto-Eintrag in einer der Subtabellen verwiesen werden können. In meinen Augen geht das sinnvoll nur über eine Schnittstelle, eben die abstrakte Klasse "Auto".
 
Deswegen auch meine Attribut-Tabelle...
Attribute die für ein Auto nicht existieren oder nicht vorhanden sind (weil nicht gepflegt), brauchst du ja nicht anlegen...
 
Ich komme nicht hinterher: Wie soll ich in @Distrilec s Variante denn Daterange-Attribute, selbst erstelle Typen, boolesche Werte etc. unterbringen? Aus dem gleichen Grund helfen mir auch JSON oder Key-Value-Pairs nicht weiter. Ich müsste dann jeweils Routinen schreiben, um bei jedem SELECT die als varchar gespeicherten Werte in das richtige Format umzuwandeln.
Deshalb scheint mir bisher die FK-Konstruktion immer noch die sinnvollste Variante, von Inheritance lasse ich die Finger.
 
Werbung:
Der Datenbank ist es egal ob du 3 oder 3000 Spalten hast... Es ist ihr aber nicht egal ob du 1 Tabelle oder 1000 hast...

Meine Frage wäre... Wie willst du das jemals auswerten? Du musst VOR deiner Abfrage schon wissen welche Tabelle(welche Automarke) du eigentlich haben willst... D.h. es ist unmöglich dein Konzept irgendeinem User zu geben... Der wird sich nämlich nicht jedesmal das Statement zurecht frickeln, nur weil er eben mal nicht Opel sondern VW haben will... Wenn du dann für jede Marke auch noch eigene Objects anlegst... Ist es sowieso vorbei...
Meine erste Frage wäre da dann auch:
Gibt es so große Unterschiede zwischen Opel und VW-Autos? Ich meine... Die haben doch alle 4 Räder/ 3-5 Türen / einen Motor (Diesel, Benzin oder Strom) / eine Motorhaube .... etc.
Was willst du denn noch abbilden? Mir fällt derzeit nichts so Hersteller-spezifisches ein, als dass ich für jeden Hersteller eigene Objects erstellen müsste...

Oder verstehe ich hier gerade irgendwas falsch?
 
Zurück
Oben