Vorgeschlagenes Schema
Zuallererst ist hier ein Beispiel für mein vorgeschlagenes Schema, auf das ich in meinem Beitrag verweisen möchte:
Clothes
----------
ClothesID (PK) INT NOT NULL
Name VARCHAR(50) NOT NULL
Color VARCHAR(50) NOT NULL
Price DECIMAL(5,2) NOT NULL
BrandID INT NOT NULL
...
Brand_1
--------
ClothesID (FK/PK) int NOT NULL
ViewingUrl VARCHAR(50) NOT NULL
SomeOtherBrand1SpecificAttr VARCHAR(50) NOT NULL
Brand_2
--------
ClothesID (FK/PK) int NOT NULL
PhotoUrl VARCHAR(50) NOT NULL
SomeOtherBrand2SpecificAttr VARCHAR(50) NOT NULL
Brand_X
--------
ClothesID (FK/PK) int NOT NULL
SomeOtherBrandXSpecificAttr VARCHAR(50) NOT NULL
Problemstellung
Ich habe eine Kleidung Tabelle , die Spalten wie hat Namen, Farbe, Preis, brandid und so weiter zu beschreiben , die Attribute für ein bestimmtes Kleidungsstück.
Hier ist mein Problem: verschiedene Marken s Kleidungs erfordert unterschiedliche Informationen. Was ist die beste Vorgehensweise, um mit einem solchen Problem umzugehen?
Beachten Sie, dass für meine Zwecke markenspezifische Informationen ab einem Kleidungseintrag gesucht werden müssen. Dies liegt daran, dass ich dem Benutzer zuerst die Informationen aus einem Kleidungseintrag anzeige. Danach muss ich die markenspezifischen Informationen verwenden, um den Artikel zu kaufen. Zusammenfassend muss zwischen clothes (from) und den brand_x- Tabellen eine Richtungsbeziehung bestehen .
Vorgeschlagene / aktuelle Lösung
Um damit umzugehen, habe ich mir folgendes Designschema überlegt:
Die Kleidertabelle enthält eine Markenspalte mit ID-Werten von 1 bis x, wobei eine bestimmte ID einer markenspezifischen Tabelle entspricht. Zum Beispiel entspricht der ID-Wert 1 der Tabelle brand_1 (die möglicherweise eine URL- Spalte enthält), ID 2 entspricht brand_2 (die möglicherweise eine Lieferantenspalte enthält ) usw.
Um einen bestimmten Kleidungseintrag mit seinen markenspezifischen Informationen zu verknüpfen, stelle ich mir vor, dass die Logik auf Anwendungsebene ungefähr so aussieht:
clothesId = <some value>
brand = query("SELECT brand FROM clothes WHERE id = clothesId")
if (brand == 1) {
// get brand_1 attributes for given clothesId
} else if (brand == 2) {
// get brand_2 attributes for given clothesId
} ... etc.
Andere Kommentare und Gedanken
Ich versuche, meine gesamte Datenbank in BCNF zu normalisieren, und obwohl mir dies eingefallen ist, macht mir der resultierende Anwendungscode große Sorgen. Es gibt keine Möglichkeit, Beziehungen zu erzwingen, außer auf Anwendungsebene, und daher fühlt sich das Design sehr kitschig und, wie ich vermute, sehr fehleranfällig an.
Forschung
Ich habe mir die vorherigen Einträge angesehen, bevor ich einen Beitrag verfasst habe. Hier ist ein Beitrag mit einem nahezu identischen Problem, das ich gefunden habe. Ich habe diesen Beitrag trotzdem verfasst, weil es den Anschein hat, als ob die einzige Antwort, die bereitgestellt wird, keine SQL- oder designbasierte Lösung enthält (dh, sie erwähnt OOP, Vererbung und Schnittstellen).
Ich bin auch ein Anfänger, wenn es um Datenbankdesign geht, und würde mich über Erkenntnisse freuen.
Offenbar gibt es weitere hilfreiche Antworten zum Stapelüberlauf:
- Hier
- Und hier
- Aaaand here (Schlüsselbegriff ist: Vererbung von Klassentabellen)
Ich habe dort auf die Lösungen verwiesen und anderen vorgeschlagen, die meine Frage finden, dies auch zu tun.
Trotz der oben angegebenen Links bin ich immer noch auf der Suche nach Antworten und würde mich über mögliche Lösungen freuen!
Ich benutze PostgreSQL.
quelle
Was Sie beschreiben, ist zumindest teilweise ein Produktkatalog. Sie haben mehrere Attribute, die allen Produkten gemeinsam sind. Diese gehören in eine gut normalisierte Tabelle.
Darüber hinaus haben Sie eine Reihe von Attributen, die markenspezifisch sind (und ich erwarte, dass sie produktspezifisch sein könnten). Was muss Ihr System mit diesen spezifischen Attributen tun? Haben Sie eine Geschäftslogik, die vom Schema dieser Attribute abhängt, oder listen Sie sie nur in einer Reihe von "label": "value" -Paaren auf?
Andere Antworten schlagen vor, einen CSV-Ansatz zu verwenden (ob dies nun der Fall ist
JSON
oderARRAY
nicht). Diese Ansätze verzichten auf die reguläre Behandlung relationaler Schemata, indem das Schema aus den Metadaten in die Daten selbst verschoben wird.Hierfür gibt es ein portables Entwurfsmuster, das sehr gut zu relationalen Datenbanken passt. Es ist EAV (Entity-Attribut-Wert). Ich bin sicher, Sie haben an vielen, vielen Orten gelesen, dass "EAV ist böse" (und es ist). Es gibt jedoch eine bestimmte Anwendung, bei der die Probleme mit EAV nicht wichtig sind, nämlich Produktattributkataloge.
Alle üblichen Argumente gegen EAV gelten nicht für einen Produktmerkmalskatalog, da Produktmerkmalswerte in der Regel nur in eine Liste oder im schlimmsten Fall in eine Vergleichstabelle übernommen werden.
Durch die Verwendung eines
JSON
Spaltentyps können Sie alle Dateneinschränkungen aus der Datenbank erzwingen und in Ihre Anwendungslogik übernehmen. Die Verwendung einer Attributtabelle für jede Marke hat außerdem die folgenden Nachteile:Es ist nicht besonders schwierig, Daten zu einem Produkt mit markenspezifischen Merkmalen abzurufen. Es ist wohl einfacher, ein dynamisches SQL mithilfe des EAV-Modells zu erstellen, als mithilfe des Table-per-Category-Modells. In Tabelle pro Kategorie benötigen Sie Reflektion (oder Ihre
JSON
), um herauszufinden, wie die Namen der Feature-Spalten lauten. Anschließend können Sie eine Liste von Elementen für eine where-Klausel erstellen. Im EAV-Modell wird dasWHERE X AND Y AND Z
zuINNER JOIN X INNER JOIN Y INNER JOIN Z
, daher ist die Abfrage etwas komplizierter, aber die Logik zum Erstellen der Abfrage ist immer noch vollständig tabellenbasiert und mehr als skalierbar, wenn Sie die richtigen Indizes erstellen.Es gibt viele Gründe, EAV nicht als allgemeinen Ansatz zu verwenden. Diese Gründe gelten nicht für einen Produktfeaturekatalog, sodass in dieser speziellen Anwendung nichts an EAV falsch ist.
Dies ist sicherlich eine kurze Antwort auf ein komplexes und kontroverses Thema. Ich habe ähnliche Fragen schon einmal beantwortet und auf die allgemeine Abneigung gegen EAV eingegangen. Beispielsweise:
Ich würde sagen, EAV wird in letzter Zeit aus meist guten Gründen seltener verwendet als früher. Ich denke jedoch, dass es auch nicht gut verstanden wird.
quelle
Verwendung von JSON und PostgreSQL
Ich denke du machst es schwieriger als es sein muss und du wirst später damit gebissen. Sie benötigen kein Entity-Attribut-Wert-Modell, es sei denn, Sie benötigen tatsächlich EAV.
An diesem Schema ist absolut nichts auszusetzen.
Jetzt können Sie es mit einem einfachen Join abfragen
Und jeder der JSON-Operatoren arbeitet in einer where-Klausel.
Fügen Sie die URLs nicht in die Datenbank ein. Sie ändern sich im Laufe der Zeit. Erstellen Sie einfach eine Funktion, die sie übernimmt.
oder Wasauchimmer. Wenn Sie PostgreSQL verwenden, können Sie sogar Hash-IDs verwenden .
Ebenfalls von besonderer Bedeutung,
jsonb
wird als Binärdatei gespeichert (daher das -'b ') und ist auch indexierbar, oder SARGable oder was auch immer die coolen Kids heutzutage nennen:CREATE INDEX ON brands USING gin ( attributes );
Der Unterschied liegt hier in der Einfachheit der Abfrage.
Wie wäre es mit einem anderen ..
quelle
Eine einfache Lösung besteht darin, alle möglichen Attribute als Spalten in die Hauptkleidungstabelle aufzunehmen und alle markenspezifischen Spalten auf null zu setzen. Diese Lösung unterbricht die Datenbanknormalisierung, ist jedoch sehr einfach zu implementieren.
quelle