Ich glaube, der Titel ist selbsterklärend. Wie erstellen Sie die Tabellenstruktur in PostgreSQL, um eine Viele-zu-Viele-Beziehung herzustellen?
Mein Beispiel:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Radu Gheorghiu
quelle
quelle
Antworten:
Die SQL DDL-Anweisungen (Data Definition Language) könnten folgendermaßen aussehen:
Ich habe einige Anpassungen vorgenommen:
Die n: m-Beziehung wird normalerweise durch eine separate Tabelle implementiert -
bill_product
in diesem Fall.Ich habe
serial
Spalten als Ersatzprimärschlüssel hinzugefügt . Betrachten Sie in Postgres 10 oder höher stattdessen eineIDENTITY
Spalte . Sehen:Ich kann das nur empfehlen, da der Name eines Produkts kaum eindeutig ist (kein guter "natürlicher Schlüssel"). Das Erzwingen der Eindeutigkeit und das Verweisen auf die Spalte in Fremdschlüsseln ist in der Regel mit einem 4-Byte
integer
(oder sogar einem 8-Bytebigint
) billiger als mit einer alstext
oder gespeicherten Zeichenfolgevarchar
.Sie keine Namen von Basisdatentypen wie verwenden
date
als Bezeichner . Dies ist zwar möglich, hat aber einen schlechten Stil und führt zu verwirrenden Fehlern und Fehlermeldungen. Verwenden Sie legale, nicht zitierte Bezeichner in Kleinbuchstaben . Verwenden Sie niemals reservierte Wörter und vermeiden Sie doppelte Anführungszeichen für gemischte Groß- und Kleinschreibung, wenn Sie können."Name" ist kein guter Name. Ich habe die Spalte der Tabelle
product
inproduct
(product_name
oder ähnlich) umbenannt. Das ist eine bessere Namenskonvention . Andernfalls , wenn Sie ein paar Tabellen in einer Join - Abfrage - etwas Sie tun eine Menge in einer relationalen Datenbank - Sie mehrere Spalten mit dem Namen „name“ am Ende mit und müssen Spaltenaliasnamen verwenden , um das Chaos in Ordnung bringen. Das ist nicht hilfreich. Ein weiteres weit verbreitetes Anti-Pattern wäre nur "id" als Spaltenname.Ich bin mir nicht sicher, wie der Name eines
bill
lauten würde.bill_id
wird in diesem Fall wahrscheinlich ausreichen.price
ist vom Datentypnumeric
, um Bruchzahlen genau wie eingegeben zu speichern (beliebiger Genauigkeitstyp anstelle des Gleitkommatyps). Wenn Sie sich ausschließlich mit ganzen Zahlen beschäftigen, machen Sie dasinteger
. Sie können beispielsweise Preise als Cent speichern .Das
amount
("Products"
in Ihrer Frage) geht in die Verknüpfungstabellebill_product
und ist ebenfalls vom Typnumeric
. Auch hier gilt,integer
wenn Sie sich ausschließlich mit ganzen Zahlen befassen.Sie sehen die Fremdschlüssel in
bill_product
? Ich habe beide erstellt, um Änderungen zu kaskadieren :ON UPDATE CASCADE
. Wenn sich aproduct_id
oderbill_id
ändern sollte, wird die Änderung auf alle abhängigen Einträge in kaskadiertbill_product
und nichts wird unterbrochen. Dies sind nur Referenzen ohne eigene Bedeutung.Ich habe auch verwendet
ON DELETE CASCADE
fürbill_id
: Wenn eine Rechnung gelöscht wird, sterben ihre Details damit.Nicht so bei Produkten: Sie möchten kein Produkt löschen, das in einer Rechnung verwendet wird. Postgres gibt einen Fehler aus, wenn Sie dies versuchen. Sie würden
product
stattdessen eine weitere Spalte hinzufügen , um veraltete Zeilen zu markieren ("soft-delete").Alle Spalten in diesem Basisbeispiel sind am Ende so
NOT NULL
, dassNULL
Werte nicht zulässig sind. (Ja, alle Spalten - Primärschlüsselspalten werdenUNIQUE NOT NULL
automatisch definiert .) Dies liegt daran, dassNULL
Werte in keiner der Spalten sinnvoll sind. Es erleichtert das Leben eines Anfängers. Aber Sie werden nicht so leicht davonkommen, Sie müssen sowieso dieNULL
Handhabung verstehen . Zusätzliche Spalten könnenNULL
Werte zulassen , Funktionen und Verknüpfungen könnenNULL
Werte in Abfragen usw. einführen .Lesen Sie das Kapitel
CREATE TABLE
im Handbuch .Primärschlüssel werden mit einem eindeutigen Index für die Schlüsselspalten implementiert , wodurch Abfragen mit Bedingungen für die PK-Spalte (n) schnell durchgeführt werden. Die Reihenfolge der Schlüsselspalten ist jedoch bei mehrspaltigen Schlüsseln relevant. Da in meinem Beispiel die PK aktiviert
bill_product
ist(bill_id, product_id)
, möchten Sie möglicherweise einen weiteren Index für just hinzufügen,product_id
oder(product_id, bill_id)
wenn Sie Abfragen haben, die nach einem bestimmtenproduct_id
und einem bestimmten suchenbill_id
. Sehen:Lesen Sie das Kapitel über Indizes im Handbuch .
quelle
bill_product
? Normalerweise sollte es so aussehen :CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. Ist das richtig?bill
. Wir benötigen den Betrag pro hinzugefügtem Artikel inbill_product
.