Ist mein Tabellenkonstrukt ein Fall für das Weglassen eines Primärschlüssels?

  • SQL

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von VB2021Aug.

    Ist mein Tabellenkonstrukt ein Fall für das Weglassen eines Primärschlüssels?

    Ich habe mal eine konzeptionelle Frage zum Thema Primary Keys. Grundsätzlich scheint jeder immer zu sagen, dass jede Tabelle unbedingt einen Primärschlüssel haben sollte (auch wenn dieser technisch natürlich keine Pflicht ist). Allerdings habe ich einen Spezialfall, wo ich unsicher bin, ob ich hier einen Primärschlüssel einfügen sollte, der im Prinzip nie genutzt wird. Er schadet nicht, kommt mir aber überflüssig vor.

    Das von mir verwendete DBMS ist MySQL bzw. MariaDB. Ich habe folgende vier Tabellen (PK=Primary Key, FK=Foreign Key):

    Quellcode

    1. Haupttabelle:
    2. ID (PK)
    3. Name (Unique)
    4. Untertabelle:
    5. ID (PK)
    6. Haupt-ID (FK)
    7. Verknüpfung-1-ID (FK)
    8. Verknüpfung-2-ID (FK, optional)
    9. Verknüpfungstabelle 1:
    10. ID (PK)
    11. Name (Unique)
    12. Verknüpfungstabelle 2:
    13. ID (PK)
    14. Name (Unique)

    Es geht in dem Fall um die Tabelle "Untertabelle" (in allen anderen Tabellen brauche ich definitiv einen Primary Key).

    Wie schon gesagt, nutze ich den PK in der besagten Tabelle nicht. Ich frage immer ab select * from Untertabelle where Haupt-ID = ?. Beim Speichern von Datensätzen in der Untertabelle plane ich, der Einfachheit halber immer alles zu löschen und dann neu einzutragen. Also beim Speichern des Hauptdatensatzes werden die Unterdatensätze immer alle neu eingetragen, was mir die Arbeit massiv vereinfacht. Oder wäre das kein gutes Vorgehen?

    Einen Primärschlüssel über die drei Spalten Haupt-ID, Verknüpfung-1-ID und Verknüpfung-2-ID zu machen, geht nicht, da Verknüpfung-2-ID optional ist (darf NULL werden).

    Welchen Weg schlagt ihr vor?
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Die Frage ist ob ein Datensatz aus Haupt-ID und Verknüpfung-1-ID sowohl mit und ohne Verknüpfung-2-ID zeitgleich existieren kann.

    Ansonsten wäre dein PK Haupt-ID und Verknüpfung-1-ID

    VG,
    Acr0most
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:
    Wenn ein Datensatz ohne Verknüpfung-2-ID existiert, darf nicht zeitgleich noch ein Datensatz mit Verknüpfung-2-ID existieren. Folgendes ist also nicht möglich:

    Haupt-ID
    Verknüpfung-1-ID
    Verknüpfung-2-ID
    1
    1
    1
    1
    1
    NULL


    Aber: folgendes muss möglich sein, daher kann der PK nicht über die ersten beiden Spalten gehen:

    Haupt-ID
    Verknüpfung-1-ID
    Verknüpfung-2-ID
    1
    1
    1
    1
    1
    2
    1
    1
    3
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum
    Hi.

    Mache auch gerade Datenbanken...

    Aus den Antworten lese ich, das in der "Untertabelle" die ID nicht gebraucht wird.
    Die Tabelle bzw. der Datensatz ist für mich wie ein Knoten (Node) der Verzweigt.
    Hauttabelle zu den Verknüpfungstabellen. (Wenn "Verknüpfungstabellen = Null" , als "Leertabelle" betrachtet wird.)

    Die Eindeutigkeit ist gegeben, auch wenn die ID entfällt, weil daraus ein Zusammengesetzter-Schlüßel wird.

    Na mal sehen ob ich damit meine "Zischentabellen" Prüfungsreif normalisiere... :)

    c.u Joshi aus HH (<- Error: Der Ort muss eine Mindestlänge von 3 Zeichen haben.") :D

    Joshi schrieb:

    Aus den Antworten lese ich, das in der "Untertabelle" die ID nicht gebraucht wird.
    Verallgemeinernd kann man das nicht sagen.
    Wenn Marcus sie nicht braucht, dann braucht er sie nicht, und gut (zumindest so lange, bis er sie doch braucht).

    Ich neige aus Bequemlichkeit dazu, PKs zu verteilen.
    Etwa wenn man einen Join formulieren muss wird das ziemlich hässlich, wenn dabei mehrere Spalten zu includieren sind.
    (also noch hässlicher als sowieso schon).

    Aber daraus ergibt sich auch eine feine Änderung im Datenmodell-Verhalten:
    Ein aus mehreren FKs zusammengesetzter PK modelliert, dass es für zwei bestimmte Datensätze nur einen Verknüpfungs-Datensatz geben kann.
    Bei zusätzlichem PK in der Verknüpfungs-Tabelle kann man dieselben Datensätze so oft wie wolle verknüppern.
    @petaod
    Was meinst du mit der ersten Spalte? Falls du damit die Haupt-ID meinst, die brauche ich. Denn natürlich können in der Haupttabelle beliebig viele Datensätze sein und zu jedem gehören beliebig viele Unterdatensätze. Für den unwahrscheinlichen Fall, dass du du die ID meinst: ja, die brauche ich nicht, daher die Frage, ob ich diese weglassen sollte (es ist jetzt der autoinkrementierte PK).

    Ein Unique Constraint über die Spalten 2+3 geht nicht (bzw. bringt nichts), da, wie gesagt, die letzte Spalte optional ist. Der Wert "NULL" wird nämlich von so einem Contraint offenbar ignoriert. Folgendes ist daher möglich (Col1+Col2 sind zusammen Unique):

    Col1
    Col2
    1
    NULL
    1
    NULL


    Noch bin ich unsicher, wie ich hier verfahren soll. Ich glaube aber fast, es gibt in diesem Fall keine schöne Lösung. Neben der Frage nach der Notwendigkeit eines PKs gibt es eben noch das Problem, dass Datensätze in der Untertabelle in gewisser Weise Unique sein sollen, aber dies durch das optionale Feld erschwert wird.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum
    Ansonsten musst du dir deine Eindeutigkeit über ein Hilfsfeld zusammensetzen und selbst prüfen.
    Du erzeugst aus Col1, Col2 und Col3 einen Hash der dann in Col4 landet mit einem Index drauf. Vor jeden Insert erzeugst du aus den neuen Daten den Hash und prüfst den gegen die DB.
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    @MrTrebron
    Keine schlechte Idee, aber in meinem Fall geht das leider auch nicht. Siehe Post #3, die obere Tabelle. Diese beiden Datensätze würden einen unterschiedlichen Hash erzeugen, sollen aber als Duplikat gelten. Ich denke, ich muss diese Duplikatsprüfung komplett in PHP machen und kann das nicht durch die Datenbank realisieren (jedenfalls nicht ohne "richtigen" Programmiercode in Form einer Stored Procedure oder ähnlichem).

    Bleibt also nur noch die Frage, ob ich den PK einfach wegmache. Da ich damit sowieso nichts prüfen kann (also bzgl. Duplikaten) und darauf auch nie zugreife, ist er wohl überflüssig.

    Und die oben am Rande gestellte Frage, ob folgendes Vorgehen in Ordnung ist (funktionieren tut es, aber ist es "schön?):

    SQL-Abfrage

    1. update haupttabelle set name = "xyz" where id = 1;
    2. delete from untertabelle where haupt-id = 1;
    3. insert into untertabelle(haupt-id, verknüpfung-1-id) values (1,1);
    4. insert into untertabelle(haupt-id, verknüpfung-1-id) values (1,2);
    5. insert into untertabelle(haupt-id, verknüpfung-1-id) values (1,3);

    Sprich: statt bei jedem Eintrag in der Untertabelle zu prüfen, ob nun ein UPDATE, DELETE oder INSERT notwendig ist, einfach immer alles löschen und neu eintragen. In dem Fall wäre es dann auch so, dass der Auto-Increment-PK immer höher wird, sollte er bleiben.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum
    Ich würde den PK hinzufügen (als Auto-Increment). Kostet praktisch nix und in gewissen Situation ist besser ihn zu haben als ihn zu brauchen, z.B.:
    • einzelnen/doppelten Datensatz löschen/ändern
    • eindeutige Sortierung
    • bestimmte Situation mit Trigger-Programmierung
    • Frameworks/Tools welche einen PK voraussetzen


    Der Delete+Insert-Ansatz ist programmiertechnisch meist deutlich einfacher zu realisieren, als die Änderungen abzuspeichern. Wenn man das ganze in einer Transaktion kapselt, finde ich das absolut in Ordnung.

    PS: Bei dem optionalen Wert könnte man statt NULL auch 0 oder einen Sonderwert abspeichern. Bringt zwar ein paar Nachteile, erlaubt aber einen PK/Unique Index über die drei Spalten zu definieren.

    3daycliff schrieb:

    PS: Bei dem optionalen Wert könnte man statt NULL auch 0 oder einen Sonderwert abspeichern. Bringt zwar ein paar Nachteile, erlaubt aber einen PK/Unique Index über die drei Spalten zu definieren.



    Der gefällt mir!
    Aber würde dennoch das o.g. Problem wieder herbeirufen, dass eigentlich eine Kombination aus 1 - 1 - 0 (1 - 1 - NULL) nicht zulässig ist wenn ein eintrag mit 1 - 1 - X existiert und umgekehrt.
    Wenn das Leben wirklich nur aus Nullen und Einsen besteht, dann laufen sicherlich genügen Nullen frei herum. :D
    Signature-Move 8o
    kein Problem mit privaten Konversationen zu Thema XY :thumbup:

    3daycliff schrieb:

    Kostet praktisch nix und in gewissen Situation ist besser ihn zu haben

    Dann lasse ich ihn drin, auch wenn ich vmtl. nie einen entsprechenden Anwendungsfall habe. Wobei der letzte der genannten natürlich interessant ist, weil z. B. phpMyAdmin einen braucht, wenn man was in der grafischen Oberfläche machen will.

    3daycliff schrieb:

    Wenn man das ganze in einer Transaktion kapselt

    Mache ich bereits so.

    3daycliff schrieb:

    Bei dem optionalen Wert könnte man statt NULL auch 0 oder einen Sonderwert abspeichern

    Leider nein, weil die Verknüpfungsfelder auf andere Tabellen verweisen. Und die haben weder einen 0-Datensatz noch einen Sonderwert-Datensatz.

    Meine Lösung sieht nun schlussendlich so aus, dass der PK drin bleibt und ich ihn munter hochzählen lasse, auch wenn ich ihn voraussichtlich niemals brauchen werde. Weiterhin werden Duplikatsprüfungen extern gemacht (wobei ich trotzdem einen Unique-Index über die Spalten gemacht habe, was aber eben nicht jedes Duplikat erwischt). Und ich wähle den "lösche alles und füge alles neu ein"-Ansatz.

    Danke an alle für den Input!
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Moinsen.

    Der Begriff der mir da fehlte war "Schlüsselkandidaten", die zusammengenommen den Schlüssel ergeben.

    Ich mache das ab jetzt auch so, das ein PK-Feld, der einfachen Verarbeitung bei Abfragen, zusätzlich zu den Schlüsselkandidaten angelegt wird (bzw. eingeplant werden).

    Ein Möglichkeit wäre den PK, mit den Werten der Schlüsselkandidaten als Hashwert zu berechnen und dann diesen (Redundant) zu nutzen.
    Von der Optimierung/Performance abgesehen auch möglich.
    Uuupsie @MrTrebron hat das ja schon erwähnt.

    Daher Danke also "Unique Auto Increment" sollte dann reichen...

    c.u. Joshi :thumbsup:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Joshi“ ()

    Hi,
    kann ich meinen Senf dazu geben?

    "Kommt darauf an." Ich sage aber mal: "Grundsätzlich Ja"

    In einer verbindungsorientierten Umgebung (Access, DAO-Recordset, ADO-Recordset) benötigst du den Schlüssel nicht, hier wird ein Cursor / Zeiger auf einem Datensatz gehalten, so dass alle Änderungen ihr Ziel finden.

    In einer verbindungslosen Umgebung, wie das im .Net DataSet gehandhabt wird, da werden die Daten in das Programm geladen und danach "sofort der Hörer aufgelegt".
    Auf diese Weise findet ein Client-Datensatz seinen Server-Datensatz nicht mehr, es sei denn, ein eindeutiger Schlüssel weist ihm den Weg.

    Meine Empfehlung: Nutze künstliche Schlüsse! Eine Auto-ID ist schnell erstellt und "kostet nix" s.o.
    Ein "sprechender Schlüssel" "Vorname" / "Ort" etc. könnte jederzeit Änderungen oder "Nicht doppelte Doppelungen" verlangen.

    ==============

    "Alles löschen und neu einfügen"
    OK, das kann im Einzelfall sinnvoll sein.
    Aber! Was passiert "auf der Festplatte"? Datenbankserver schreiben Änderungen oft in einen eigenen Speicherbereich und müssen dann irgendwann die Datenbank neu zusammenfassen.
    Welche und wie viele Indizes müssen neu berechnet und geschrieben werden?
    Ich würde lieber 3 Datensätze über "UPDATE ... WHERE..." aktualisieren, als 100 Datensätze zu löschen und neu anzulegen, nur weil ich keine Lust auf eine nutzlose "ID" gehabt hätte.

    Und wenn du ein unglückliches "DELETE Cascade" gesetzt hast .... =O

    Ist nur so ein Gedanke.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB2021Aug“ ()

    VB2021Aug schrieb:

    Meine Empfehlung: Nutze künstliche Schlüsse!

    Meinst du damit sowas wie eine autoinkrementierte ID? Denn um die Wegrationalisierung dieser ging es und jetzt bleibt sie aber drin.

    VB2021Aug schrieb:

    Ich würde lieber 3 Datensätze über "UPDATE ... WHERE..." aktualisieren

    Wenn's jedes Mal nur ein UPDATE wäre, wäre es OK. Aber es ist INSERT für neue, UPDATE für vorhandene und DELETE für die, die gelöscht wurden. D. h. ich bekomme eine Liste und muss dann zunächst alle löschen, die nicht angekommen sind. Und dann für jeden erhaltenen Eintrag prüfen, ob eben INSERT oder UPDATE notwendig ist.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum

    Marcus Gräfe schrieb:

    Aber es ist INSERT für neue, UPDATE für vorhandene und DELETE für die, die gelöscht wurden.
    Dassis interessant.
    Das ist genau, wofür im .Net-Bereich die DataAdapter für zuständig sind.
    Die bekommen eine DataTable übergeben, die speziell nur Änderungen enthält, also INSERTs, UPDATEs, DELETEs (kann auch unmodifiziertes drinne sein, wird aber übergangen).
    Und die handeln das in richtiger Weise, ohne dass dafür die ganze Db-Tabelle neu geschrieben werden müsste.
    Aber in .Net bist du garnet unterwegs, odr?

    ErfinderDesRades schrieb:

    Aber in .Net bist du garnet unterwegs, odr?

    Leider nein, bin in diesem Fall in PHP unterwegs. Ich erhalte ein JSON-Objekt, packe dies aus und muss dann jeden Datensatz einzeln an die DB schicken, inkl. selbst zusammenbauen der SQL-Anweisung (aber natürlich arbeite ich mit Prepared Statements).
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum

    Marcus Gräfe schrieb:


    Meinst du damit sowas wie eine autoinkrementierte ID?


    Sorry, dass ich hier den "Schlaubi Schlumpf" abgebe ;) (und die Beantwortung deiner Frage hilft dir im konkreten Fall auch nicht weiter)

    "Künstliche Schlüssel": das ist ein Fachbegriff in der Datenbankentwicklung und meint, dass dieses Feld keinerlei inhaltliche Bedeutung hat, eben künstlich ist.
    "Max Müller aus Berlin" -> "MaMueBln" sowas wäre ein "Sprechender Schlüssel" und würde sofort Probleme bereiten, wenn der Mann umzieht oder einen anderen Namen annimmt.

    Ob ein Künstlicher schlüssel eine Zahl ist, oder aus Zahlen und Buchstaben besteht, ist zunächst nicht festgelegt, aber mit AutoInkrement benötigst du keinerlei zusätzlichen Programmcode.
    In besonderen Fällen wird eine Zufallszahl statt AutoIncrement gefordert, etwa zum Datenschutz ober bei Replikation.