Vorausgesetzt, Sku und ItemNumber implizieren immer eindeutige Werte
Ich bin der Meinung, dass Sie die Antwort bereits gefunden haben, indem Sie festgestellt haben, dass ItemNumber konzeptionell eine optionale Eigenschaft ist. Das heißt, wenn Sie festgestellt haben, dass dies nicht für jedes einzelne der vom Entitätstyp " Produkt" dargestellten Vorkommen gilt, die durch Zeilen auf logischer Ebene dargestellt werden . Daher sollte die item_number
Spalte in der product
Tabelle nicht als ALTERNATIVER SCHLÜSSEL (AK der Kürze halber) deklariert werden , wie Sie zu Recht betont haben.
In dieser Hinsicht ist Ihr Szenario B durchaus vernünftig, wie die folgende Formulierung auf konzeptioneller Ebene zeigt:
- Ein Produkt kann eine Artikelnummer haben oder nicht .
Mit anderen Worten, es gibt ein Kardinalitätsverhältnis von Eins zu Null oder Eins (1: 0/1) zwischen Produkt und Artikelnummer .
Dann, ja, sollten Sie eine neue Tabelle einführen, um mit der optionalen Spalte umzugehen, und ich stimme zu, dass dies product_item_number
ein sehr beschreibender Name dafür ist. Diese Tabelle sollte sku
als PRIMARY KEY (PK) eingeschränkt sein, um sicherzustellen, dass nicht mehr als eine Zeile mit demselben sku
Wert wie Sie eingefügt wird.
Es ist auch wichtig zu erwähnen, dass dies product_item_number.sku
ebenso eine Einschränkung sein sollte wie ein AUSLÄNDISCHER SCHLÜSSEL (FK), auf den verwiesen wird product.sku
.
Hier ist ein Beispiel für ein SQL-DDL-Design auf logischer Ebene, das die vorherigen Vorschläge veranschaulicht:
-- You should determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on your business context characteristics.
-- Also, you should make accurate tests to define
-- the most convenient INDEXing strategies.
CREATE TABLE product (
sku TEXT NOT NULL,
name TEXT NOT NULL,
price NUMERIC NOT NULL,
quantity NUMERIC NOT NULL,
--
CONSTRAINT product_PK PRIMARY KEY (sku),
CONSTRAINT product_AK UNIQUE (name), -- AK.
CONSTRAINT valid_price_CK CHECK (price > 0),
CONSTRAINT valid_quantity_CK CHECK (quantity > 0)
);
CREATE TABLE product_item_number (
sku TEXT NOT NULL, -- To be constrained as PK and FK to ensure the 1:0/1 correspondence ratio between the relevant rows.
item_number TEXT NOT NULL,
--
CONSTRAINT product_item_number_PK PRIMARY KEY (sku),
CONSTRAINT product_item_number_AK UNIQUE (item_number), -- In this context, ‘item_number’ is an AK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (sku)
REFERENCES product (sku)
);
Getestet auf PostgreSQL 11 in dieser db <> Geige .
Darüber hinaus gibt es eine andere konzeptionelle Formulierung, die bei der Gestaltung des oben vorgestellten Datenbankdesigns hilfreich ist:
- Wenn vorhanden, muss die Artikelnummer eines Produkts eindeutig sein.
Wo also die item_number
Spalte tatsächlich als AK deklariert werden soll, befindet sich genau dort in der product_item_number
Tabelle, da diese Spalte nur dann einen Eindeutigkeitsschutz erfordert, wenn der entsprechende Wert angegeben wird. Daher müssen die Einschränkungen UNIQUE und NOT NULL entsprechend konfiguriert werden.
Fehlende Werte und die „Interpretation der geschlossenen Welt“
Die zuvor beschriebene logische SQL-DDL-Anordnung ist ein Beispiel für den relationalen Ansatz zur Behandlung fehlender Werte, obwohl er nicht der beliebteste - oder übliche - ist. Dieser Ansatz bezieht sich auf die „Interpretation der geschlossenen Welt“ - oder „Annahme“ -. Wenn Sie diese Position einnehmen, werden (a) die in der Datenbank aufgezeichneten Informationen immer als wahr angesehen , und (b) die Informationen, die nicht in dieser Datenbank aufgezeichnet sind, werden jederzeit als falsch angesehen . Auf diese Weise behält man ausschließlich bekannte Tatsachen bei .
Wenn ein Benutzer im vorliegenden Geschäftsszenario alle Datenpunkte bereitstellt, die in der product
Tabelle enthalten sind, müssen Sie die entsprechende Zeile einfügen. Wenn und nur wenn der Benutzer das item_number
Datum verfügbar gemacht hat, müssen Sie auch das product_item_number
Gegenstück EINFÜGEN . Falls der item_number
Wert unbekannt ist oder einfach nicht zutrifft, fügen Sie keine product_item_number
Zeile ein, und das ist es.
Mit dieser Methode vermeiden Sie halten NULL Marken / Marker in Ihre Basistabellen -und die logischen Ebene Konsequenzen , die werde ich ausführlich in der nächsten section-, aber Sie sollten sich bewusst sein , dass dies ein „umstritten“ in der Datenbank - Administration Bereich. In diesem Punkt finden Sie möglicherweise die Antworten auf die Frage zum Stapelüberlauf mit dem Titel:
Die beliebte Vorgehensweise
Ich vermute jedoch, dass das beliebte - oder übliche - Verfahren darin besteht, eine einzelne product
Tabelle zu haben , die die item_number
Spalte enthält, die wiederum als NULL-fähig festgelegt und gleichzeitig mit einer EINZIGARTIGEN Einschränkung definiert wird. So wie ich es sehe, würde dieser Ansatz Ihre Datenbank und die anwendbaren Datenmanipulationsvorgänge weniger elegant machen (wie z. B. in dieser hervorragenden Antwort zum Stapelüberlauf gezeigt ), aber es ist eine Möglichkeit.
Siehe die aufeinander folgenden DDL-Anweisungen, die diese Vorgehensweise veranschaulichen:
CREATE TABLE product (
sku TEXT NOT NULL,
name TEXT NOT NULL,
price NUMERIC NOT NULL,
quantity NUMERIC NOT NULL,
item_number TEXT NULL, -- Accepting NULL marks.
--
CONSTRAINT product_PK PRIMARY KEY (sku),
CONSTRAINT product_AK1 UNIQUE (name), -- AK.
CONSTRAINT product_AK2 UNIQUE (item_number), -- Being ‘NULLable’, this is not an AK.
CONSTRAINT valid_price_CK CHECK (price > 0),
CONSTRAINT valid_quantity_CK CHECK (quantity > 0)
);
Getestet auf PostgreSQL 11 in dieser db <> Geige .
Nachdem item_number
eine Spalte erstellt wurde, die NULL-Werte enthalten kann, ist es logischerweise nicht richtig zu sagen, dass es sich um eine AK handelt. Darüber hinaus würden Sie mehrdeutige NULL-Zeichen speichern - die keine Werte sind, unabhängig davon, ob sie in der PostgreSQL-Dokumentation so gekennzeichnet sind -. Daher kann argumentiert werden, dass die Tabelle keine ordnungsgemäße Darstellung einer angepassten mathematischen Beziehung darstellt und Normalisierungsregeln dies nicht können darauf angewendet werden.
Da ein NULL-Wert angibt, dass ein Spaltenwert (1) unbekannt oder (2) nicht anwendbar ist , kann nicht zu Recht angegeben werden, dass diese Marke zum item_number
gültigen Wertebereich gehört. Wie Sie wissen, sagt diese Art von Marke etwas über den „Status“ eines realen Wertes aus, aber es ist kein Wert selbst und verhält sich natürlich nicht als solcher - und das ist übrigens erwähnenswert NULL-Werte verhalten sich in den verschiedenen SQL-Datenbankverwaltungssystemen unterschiedlich, selbst in verschiedenen Versionen desselben Datenbankverwaltungssystems.
Wenn dann (i) der Wertebereich einer bestimmten Spalte und (ii) die Bedeutung, die diese Spalte trägt, aufgrund der Einbeziehung von NULL-Werten nicht ganz klar ist:
Trotz der theoretischen und praktischen Auswirkungen auf die Datenmanipulation, die sich auf die Beibehaltung von NULL-Zeichen in einer Datenbank beziehen, ist dies der Ansatz, um fehlende Daten zu behandeln, die seitdem in der überwiegenden Mehrheit der auf SQL-Plattformen erstellten Datenbanken zu finden sind Es ermöglicht das Anhängen von Spalten für optionale Werte an die Basistabellen von Bedeutung und entzieht sich daher der Erstellung von (a) einer ergänzenden Tabelle und (b) den zugehörigen Aufgaben.
Die Entscheidung
Ich habe die beiden Alternativen vorgestellt, damit Sie selbst bestimmen können, welche zur Erreichung Ihrer Ziele besser geeignet ist.
Angenommen, die Werte Sku und ItemNumber können eventuell dupliziert werden
Es gibt einige Punkte Ihrer Frage, die meine Aufmerksamkeit auf besondere Weise erregt haben, deshalb habe ich sie aufgelistet:
Manchmal (vielleicht 3% bis 5% der Zeit) entspricht die item_number tatsächlich der SKU. Das heißt, einer meiner Lieferanten bringt insbesondere Produkte an seinen Produkten an, von denen ich vermute, dass sie keine weltweit eindeutige SKU sind, die nach ihrer Artikelnummer gestaltet ist.
[…] Es kann Fälle geben, in denen ein Lieferant eine Katalognummer mit einem anderen Sku recycelt (vielleicht?), Oder Situationen, in denen zwei Hersteller beide ein "d57-rot" oder ähnliches herstellen. In diesem Fall müsste ich den beleidigenden item_numbers programmgesteuert Herstellernamen oder ähnliches voranstellen.
Ein SKU wird in meiner Domain immer eindeutig sein (Es ist unwahrscheinlich, dass die geringe Anzahl von nicht global eindeutigen, vom Lieferanten bereitgestellten SKUs jemals kollidiert).
Diese Punkte können bemerkenswerte Auswirkungen haben, da sie darauf hindeuten, dass:
Die ItemNumber- Werte können möglicherweise dupliziert werden. In diesem Fall können Sie die Kombination von zwei verschiedenen Informationen mit unterschiedlichen Bedeutungen in derselben Spalte bewerten.
Es ist wahrscheinlich, dass sich die Sku- Werte schließlich wiederholen (selbst wenn es sich um eine kleine Anzahl wiederholter Sku- Instanzen handelt).
In diesem Zusammenhang ist anzumerken, dass zwei Hauptziele einer Datenmodellierungsübung darin bestehen, (1) jedes einzelne Signifikanzdatum zu bestimmen und (2) zu verhindern, dass mehr als eines davon in derselben Spalte erhalten bleibt. Diese Faktoren erleichtern beispielsweise die Abgrenzung einer stabilen und vielseitigen Datenbankstruktur und tragen zur Vermeidung doppelter Informationen bei, wodurch die Datenwerte über die jeweiligen Einschränkungen hinweg mit den Geschäftsregeln in Einklang gehalten werden können.
Alternative zum Umgang mit Sku- Duplikaten: Einführung einer manufacturer
Tabelle in das Szenario
Unter der Bedingung, dass derselbe Sku- Wert von verschiedenen Herstellern gemeinsam genutzt werden kann , können Sie daher eine zusammengesetzte PK-Einschränkung in der product
Tabelle verwenden, die sich aus (i) der Hersteller-PK-Spalte und (ii) zusammensetzt sku
. Z.B:
CREATE TABLE manufacturer (
manufacturer_number INTEGER NOT NULL, -- This could be something more meaningful, e.g., ‘manufacturer_code’.
name TEXT NOT NULL,
--
CONSTRAINT manufacturer_PK PRIMARY KEY (manufacturer_number),
CONSTRAINT manufacturer_AK UNIQUE (name) -- AK.
);
CREATE TABLE product (
manufacturer_number INTEGER NOT NULL,
sku TEXT NOT NULL,
name TEXT NOT NULL,
price NUMERIC NOT NULL,
quantity NUMERIC NOT NULL,
--
CONSTRAINT product_PK PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
CONSTRAINT product_AK UNIQUE (name), -- AK.
CONSTRAINT product_TO_manufacturer_FK FOREIGN KEY (manufacturer_number)
REFERENCES manufacturer (manufacturer_number),
CONSTRAINT valid_price_CK CHECK (price > 0),
CONSTRAINT valid_quantity_CK CHECK (quantity > 0)
);
Wenn die ItemNumber die Wahrung der Eindeutigkeit verlangt, wenn sie anwendbar ist , kann die product_item_number
Tabelle wie folgt strukturiert werden:
CREATE TABLE product_item_number (
manufacturer_number INTEGER NOT NULL,
sku TEXT NOT NULL,
item_number TEXT NOT NULL,
--
CONSTRAINT product_item_number_PK PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
CONSTRAINT product_item_number_AK UNIQUE (item_number), -- AK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku)
REFERENCES product (manufacturer_number, sku)
);
Getestet auf PostgreSQL 11 in dieser db <> Geige .
Für den Fall , dass ItemNumber ist nicht zu verhindern Duplikate benötigen, entfernen Sie einfach die UNIQUE - Einschränkung für eine solche Spalte erklärt, wie es in den nächsten DDL - Anweisungen gezeigt:
CREATE TABLE product_item_number (
manufacturer_number INTEGER NOT NULL,
sku TEXT NOT NULL,
item_number TEXT NOT NULL, -- In this case, ‘item_number’ does not require a UNIQUE constraint.
--
CONSTRAINT product_item_number_PK PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku)
REFERENCES product (manufacturer_number, sku)
);
Angenommen , ItemNumber bedeutet tatsächlich, dass wiederholte Werte ausschließlich in Bezug auf den zugeordneten Hersteller vermieden werden , können Sie eine zusammengesetzte EINZIGARTIGE Einschränkung einrichten, die aus manufacturer_number
und besteht item_number
, wie in den folgenden Codezeilen gezeigt:
CREATE TABLE product_item_number (
manufacturer_number INTEGER NOT NULL,
sku TEXT NOT NULL,
item_number TEXT NOT NULL,
--
CONSTRAINT product_item_number_PK PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
CONSTRAINT product_item_number_AK UNIQUE (manufacturer_number, item_number), -- Composite AK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku) -- Composite FK.
REFERENCES product (manufacturer_number, sku)
);
Wenn Sku- Werte immer eindeutig sind, aber ein bestimmter ItemNumber- Wert von verschiedenen Herstellern gemeinsam genutzt werden kann
Wenn Sie garantieren können, dass Product.Sku niemals Duplikate impliziert, aber eine ItemNumber möglicherweise von verschiedenen Herstellern verwendet wird , können Sie Ihre Datenbank wie folgt konfigurieren:
CREATE TABLE manufacturer (
manufacturer_number INTEGER NOT NULL,
name TEXT NOT NULL,
--
CONSTRAINT manufacturer_PK PRIMARY KEY (manufacturer_number),
CONSTRAINT manufacturer_AK UNIQUE (name) -- AK.
);
CREATE TABLE product (
sku TEXT NOT NULL,
name TEXT NOT NULL,
price NUMERIC NOT NULL,
quantity NUMERIC NOT NULL,
--
CONSTRAINT product_PK PRIMARY KEY (sku),
CONSTRAINT product_AK UNIQUE (name), -- AK.
CONSTRAINT valid_price_CK CHECK (price > 0),
CONSTRAINT valid_quantity_CK CHECK (quantity > 0)
);
CREATE TABLE product_item_number (
sku TEXT NOT NULL,
manufacturer_number INTEGER NOT NULL,
item_number TEXT NOT NULL,
--
CONSTRAINT product_item_number_PK PRIMARY KEY (sku, manufacturer_number),
CONSTRAINT product_item_number_AK UNIQUE (manufacturer_number, item_number), -- In this context, ‘manufacturer_number’ and ‘item_number’ compose an AK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (sku)
REFERENCES product (sku),
CONSTRAINT product_item_number_TO_manufacturer_FK FOREIGN KEY (manufacturer_number)
REFERENCES manufacturer (manufacturer_number)
);
Getestet auf PostgreSQL 11 in dieser db <> Geige .
Überlegungen zur physischen Ebene
Wir haben den genauen Typ und die Größe der product.sku
Spalte nicht erörtert, aber wenn sie in Bezug auf Bytes „groß“ ist, kann dies die Datenabrufgeschwindigkeit Ihres Systems beeinträchtigen - aufgrund von Aspekten der damit verbundenen physischen Abstraktionsebene mit z. B. der Größe der Indizes und der Speicherplatznutzung -.
Auf diese Weise möchten Sie möglicherweise die Einbindung einer INTEGER-Spalte bewerten, die eine schnellere Antwort bietet als eine möglicherweise „schwere“ TEXT-Spalte - aber alles hängt von den genauen Merkmalen der verglichenen Spalten ab -. Es kann durchaus sein, product_number
dass, wie erwartet, ein numerischer Wert in einer Sequenz dargestellt wird, die für den Satz von aufgezeichneten steht products
.
Eine Expository-Anordnung, die dieses neue Element enthält, ist die folgende:
CREATE TABLE product (
product_number INTEGER NOT NULL,
sku TEXT NOT NULL,
name TEXT NOT NULL,
price NUMERIC NOT NULL,
quantity NUMERIC NOT NULL,
--
CONSTRAINT product_PK PRIMARY KEY (sku),
CONSTRAINT product_AK UNIQUE (name), -- AK.
CONSTRAINT valid_price_CK CHECK (price > 0),
CONSTRAINT valid_quantity_CK CHECK (quantity > 0)
);
CREATE TABLE product_item_number
(
product_number INTEGER NOT NULL,
item_number TEXT NOT NULL,
--
CONSTRAINT product_item_number_PK PRIMARY KEY (product_number),
CONSTRAINT product_item_number_AK UNIQUE (item_number), -- AK.
CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (product_number)
REFERENCES product (product_number)
);
Ich empfehle dringend, umfangreiche Testsitzungen mit einer beträchtlichen Datenlast durchzuführen, um zu entscheiden, welche Schlüssel - physisch gesehen - bequemer sind, wobei immer die gesamten Datenbankfunktionen (Anzahl der Spalten aller Tabellen, Typ und Größe von) zu berücksichtigen sind die Spalten, die Einschränkungen und die zugrunde liegenden Indizes usw.).
Ähnliches Szenario
Ihr Geschäftsumfeld von Interesse weist eine gewisse Ähnlichkeit mit dem in diesen Beiträgen behandelten Szenario auf , sodass Sie möglicherweise einige der besprochenen Punkte als relevant erachten.
Wenn Ihr Attribut
item_number
eindeutig ist, können Sie es in Ihrer ursprünglichen Tabelle belassen, auch wenn es Nullwerte haben kann. Tatsächlich heißt es im PostgreSQL- Handbuch :Das könnte also die richtige Lösung sein:
Das ist effizienter als Lösung B und einfacher zu programmieren als Lösung C.
Beachten Sie, dass diese Lösung normalisiert ist, sodass Sie weder Redundanz noch Anomalien beim Einfügen / Löschen haben.
Zusatz
Damit eine Beziehung formal in der Boyce Codd-Normalform vorliegt (die strenger als die dritte Normalform ist), muss die Determinante für jede Abhängigkeit ein (Super-) Schlüssel sein. Beachten Sie jedoch zunächst, dass die Normalisierungstheorie normalerweise keine Nullwerte behandelt. Siehe zum Beispiel das Buch von Elmasri, Navathe, "Fundamental of Database Systems". 6. Ausgabe, 2010:
In diesem Fall haben wir zumindest die Abhängigkeit:
und in der Tat
sku
ist ein Schlüssel für die Beziehung.Angenommen, es gibt keine Nullwerte. Wenn Sie
item_number
eindeutig sein möchten , besteht eine weitere Abhängigkeit:und so
item_number
ist ein weiterer Schlüssel.In dieser Beziehung gibt es keine anderen funktionalen Abhängigkeiten, ein Teil von denen, die von diesen beiden abgeleitet wurden, und beide Abhängigkeiten verletzen nicht die BCNF (beide Determinanten sind Schlüssel). Die Beziehung ist also in Boyce Codd Normalform.
Wenn Sie jedoch berücksichtigen, dass
item_number
dies Nullwerte haben kann, können Sie davon ausgehen, dass die zweite Abhängigkeit nicht gilt, sodass sich die Beziehung wieder in BCNF befindet.quelle