it-swarm.com.de

Wie implementiere ich eine Viele-zu-Viele-Beziehung in PostgreSQL?

Ich glaube, der Titel ist selbsterklärend. Wie erstellt man die Tabellenstruktur in PostgreSQL, um eine Viele-zu-Viele-Beziehung herzustellen?.

Mein Beispiel:

Product(name, price);
Bill(name, date, Products);
64
Radu Gheorghiu

Die SQL-DDL-Anweisungen (Data Definition Language) könnten folgendermaßen aussehen:

CREATE TABLE product (
  product_id serial PRIMARY KEY  -- implicit primary key constraint
, product    text NOT NULL
, price      numeric NOT NULL DEFAULT 0
);

CREATE TABLE bill (
  bill_id  serial PRIMARY KEY
, bill     text NOT NULL
, billdate date NOT NULL DEFAULT CURRENT_DATE
);

CREATE TABLE bill_product (
  bill_id    int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE
, product_id int REFERENCES product (product_id) ON UPDATE CASCADE
, amount     numeric NOT NULL DEFAULT 1
, CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id)  -- explicit pk
);

Ich habe ein paar Anpassungen vorgenommen:

  • Die Beziehung n: m wird normalerweise durch eine separate Tabelle implementiert - in diesem Fall bill_product.

  • Ich habe serial Spalten als Ersatz-Primärschlüssel hinzugefügt . Ich kann das nur empfehlen, da der Name eines Produkts kaum eindeutig ist. Das Erzwingen der Eindeutigkeit und das Referenzieren der Spalte in Fremdschlüsseln ist mit einem 4-Byte-integer viel billiger als mit einer Zeichenfolge, die als text oder varchar gespeichert ist.
    Betrachten Sie in Postgres 10 oder höher stattdessen eine IDENTITY column . Einzelheiten:

  • Verwenden Sie keine Namen grundlegender Datentypen wie date als Bezeichner . Dies ist zwar möglich, aber der Stil ist schlecht und führt zu verwirrenden Fehlern und Fehlermeldungen. Verwenden Sie legal, Kleinbuchstaben, nicht zitierte Bezeichner . Verwenden Sie niemals reservierte Wörter und vermeiden Sie doppelte Anführungszeichen, wenn Sie können.

  • name ist kein guter Name. Ich habe die name -Spalte der Tabelle product in product umbenannt. Das ist eine bessere Namenskonvention . Andernfalls haben Sie beim Verknüpfen mehrerer Tabellen in einer Abfrage, die Sie in einer relationalen Datenbank viel ausführen, mehrere Spalten mit dem Namen name und müssen column verwenden Aliase, um das Chaos zu sortieren. Das ist nicht hilfreich. Ein weiteres verbreitetes Anti-Pattern wäre nur id als Spaltenname.
    Ich bin mir nicht sicher, wie der Name eines bill lauten würde. Vielleicht kann in diesem Fall bill_id Der Name sein.

  • price ist vom Datentyp numeric zum Speichern von Bruchzahlen genau wie eingegeben (beliebiger Genauigkeitstyp statt Gleitkommatyp). Wenn Sie sich ausschließlich mit ganzen Zahlen beschäftigen, machen Sie das integer. Zum Beispiel könnten Sie Preise als Cent sparen.

  • Das amount ("Products" In Ihrer Frage) geht in die Verknüpfungstabelle bill_product Und ist ebenfalls vom Typ numeric. Wieder integer, wenn Sie sich ausschließlich mit ganzen Zahlen befassen.

  • Sie sehen die Fremdschlüssel in bill_product? Ich habe beides erstellt, um Änderungen zu kaskadieren (ON UPDATE CASCADE): Sollte sich ein product_id Oder bill_id Ändern, wird die Änderung auf alle abhängigen Einträge in bill_product Und auf nichts kaskadiert geht kaputt.
    Ich habe auch ON DELETE CASCADE Für bill_id Verwendet: Wenn Sie eine Rechnung löschen, werden die Details damit gelöscht.
    Nicht so bei Produkten: Sie möchten kein Produkt löschen, das in einer Rechnung verwendet wird. Postgres wird einen Fehler auslösen, wenn Sie dies versuchen. Sie würden product eine weitere Spalte hinzufügen, um stattdessen veraltete Zeilen zu markieren.

  • Alle Spalten in diesem grundlegenden Beispiel haben den Wert NOT NULL, daher sind NULL -Werte nicht zulässig. (Ja, alle Spalten - In einem Primärschlüssel verwendete Spalten werden automatisch UNIQUE NOT NULL Definiert.) Dies ist darauf zurückzuführen, dass NULL -Werte in keinem der Schlüssel sinnvoll sind Säulen. Es erleichtert einem Anfänger das Leben. Aber Sie werden nicht so leicht davonkommen, Sie müssen NULL handling sowieso verstehen. Zusätzliche Spalten erlauben möglicherweise NULL Werte, Funktionen und Verknüpfungen können NULL Werte in Abfragen usw. einfügen.

  • Lesen Sie das Kapitel über 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 ausgeführt werden. Die Reihenfolge der Schlüsselspalten ist jedoch bei mehrspaltigen Schlüsseln relevant. Da die PK für bill_product In meinem Beispiel auf (bill_id, product_id) Eingestellt ist, möchten Sie möglicherweise einen weiteren Index für nur product_id Oder (product_id, bill_id) Hinzufügen, wenn Sie nach Abfragen suchen gegeben ein product_id und kein bill_id. Einzelheiten:

  • Lesen Sie das Kapitel über Indexe im Handbuch .

233