Normalisieren einer Tabelle mit einem Feld, das eine Zeile im Allgemeinen eindeutig identifiziert, aber manchmal null ist

7

vergib mir, wenn dies schon einmal gefragt und beantwortet wurde.

Ich arbeite an einem Schema für ein Bestandsverwaltungssystem, das in PostgreSQL implementiert werden soll. Alle unsere Produkte und Dienstleistungen haben einen Sku. Die meisten unserer Produkte stammen vom Hersteller oder Händler mit einer separaten "Artikelnummer" (unabhängig davon, ob es sich um die Katalognummer eines Händlers oder die Modellnummer des Herstellers handelt). Allerdings haben nicht alle eine solche Nummer. Wir haben kleine Baugruppen, die wir im eigenen Haus herstellen und die im Allgemeinen keine Artikelnummern haben. Unsere Dienstleistungen haben keine Artikelnummern. Aus diesen Gründen ist die folgende CREATE TABLE für mich sinnvoll.

Szenario A:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number   text -- hmmm...
);

Ich habe jedoch zwei Probleme damit.

  1. Manchmal (vielleicht 3% bis 5% der Zeit), ist der item_number tatsächlich gleich zu 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.

  2. Unabhängig davon, ob sie der SKU entspricht oder nicht, reicht die Artikelnummer (sofern vorhanden) in praktisch jedem Fall aus, um ein Produkt in der Domäne meines kleinen Geschäfts eindeutig zu identifizieren.

Ich mache mir Sorgen, dies auf 3NF zu normalisieren. Wenn item_number manchmal null ist, kann es offensichtlich nicht als alternativer Schlüssel deklariert werden. Aber semantisch ist es eine eindeutige Kennung, wo sie existiert, in jedem Fall, den ich mir vorstellen kann. Ist meine obige Tabelle, in der jedes Attribut funktional vom Nicht-Primat-Attribut item_number abhängig ist , wenn item_number existiert , normalisiert? Ich denke nein, aber ich bin sicherlich kein Experte. Ich dachte an Folgendes:

Szenario B.

CREATE TABLE product (
   sku            text PRIMARY KEY REFERENCES product_item_number (sku),
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
);

CREATE TABLE product_item_number (
   sku            text PRIMARY KEY,
   item_number    text
);

Da es wirklich nicht erforderlich ist, die funktionale Abhängigkeit item_number -> price, item_number -> quantity usw. beizubehalten, erscheint mir Szenario B irgendwie vernünftig. Ich werde kein Nicht-Prim-Attribut haben, das andere Nicht-Prim-Attribute bestimmt.

Meine letzte Idee war, einfach die SKU als Artikelnummer in allen Fällen zu verwenden, in denen die Artikelnummer ansonsten nicht vorhanden ist, aber ich frage mich, ob dies eine gute Vorgehensweise ist.

Szenario C.

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE NOT NULL -- alternate key???
);

Mein Problem mit Szenario C ist, dass es Fälle geben kann, 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.

Natürlich denke ich vielleicht darüber nach.

Danke fürs Lesen. Ein paar Klarstellungen gemäß den Kommentaren von MDCCL:

  • 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).
  • Die item_number ist ein öffentlich zugängliches Attribut, das sowohl von Kunden als auch manchmal von mir zur Identifizierung von Produkten verwendet wird. Angenommen, ein Kunde überspringt meine Website und ruft mich an, um mich zu fragen, ob ich xyz-white habe. Die item_number hilft dabei, Mehrdeutigkeiten zu beseitigen. Die Artikelnummern sind meiner Erfahrung nach eindeutig (das heißt, es gibt keine Gegenbeispiele in meinem Inventar), aber das ist per se keine Regel. Ich könnte eines Tages eine Kollision mit dem Namensraum item_number haben. In diesem Fall würde ich möglicherweise die ersten drei Buchstaben des Herstellernamens der Artikelnummer voranstellen.
  • item_numbers existieren nicht immer. Ich nehme an, ich könnte eine Art "Ersatz-Artikelnummer" für diejenigen ohne eine bereitstellen, aber eine beliebige Artikelnummer wäre kontraproduktiv. Wie oben erläutert, sollte eine item_number vorhanden sein, um mich und meine Kunden bei der Unterscheidung zwischen Produkten zu unterstützen. Sie könnten glauben, dass sie das falsche Produkt betrachten, wenn die item_number etwas ist, das ich mir selbst ausgedacht habe. Ich bin mir nicht sicher.
Harley
quelle

Antworten:

9

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_numberSpalte in der productTabelle 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_numberein sehr beschreibender Name dafür ist. Diese Tabelle sollte skuals PRIMARY KEY (PK) eingeschränkt sein, um sicherzustellen, dass nicht mehr als eine Zeile mit demselben skuWert wie Sie eingefügt wird.

Es ist auch wichtig zu erwähnen, dass dies product_item_number.skuebenso 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_numberSpalte tatsächlich als AK deklariert werden soll, befindet sich genau dort in der product_item_numberTabelle, 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 productTabelle enthalten sind, müssen Sie die entsprechende Zeile einfügen. Wenn und nur wenn der Benutzer das item_numberDatum verfügbar gemacht hat, müssen Sie auch das product_item_numberGegenstück EINFÜGEN . Falls der item_numberWert unbekannt ist oder einfach nicht zutrifft, fügen Sie keine product_item_numberZeile 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 productTabelle zu haben , die die item_numberSpalte 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_numbereine 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_numbergü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:

  • Wie kann man die relevanten funktionalen Abhängigkeiten bewerten und definieren?

  • Wie kann es identifiziert und als PRIMARY oder ALTERNATE KEY deklariert werden (wie im Fall von item_number)?

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 manufacturerTabelle 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 productTabelle 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_numberTabelle 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_numberund 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.skuSpalte 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_numberdass, 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.

MDCCL
quelle
1
Hallo @MDCCL, Ihre Überarbeitung ist sehr aufschlussreich, insbesondere der Vorschlag, den ich in Betracht ziehe, zusammengesetzte Schlüssel zu verwenden. Vielen Dank für die bewusste Erklärung.
Harley
Hallo, @Harley, es ist mir ein Vergnügen. Wenn es Aspekte gibt, die Sie behandeln möchten, lassen Sie es mich einfach wissen. Prost.
MDCCL
3

Wenn Ihr Attribut item_numbereindeutig 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 :

Für die Zwecke einer eindeutigen Einschränkung werden Nullwerte nicht als gleich angesehen.

Das könnte also die richtige Lösung sein:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL,
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE
);

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:

Es gibt noch keine vollständig zufriedenstellende relationale Designtheorie, die NULL-Werte enthält

In diesem Fall haben wir zumindest die Abhängigkeit:

sku  name, price, quantity, item_number

und in der Tat skuist ein Schlüssel für die Beziehung.

Angenommen, es gibt keine Nullwerte. Wenn Sie item_numbereindeutig sein möchten , besteht eine weitere Abhängigkeit:

item_number  sku, name, price, quantity

und so item_numberist 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_numberdies Nullwerte haben kann, können Sie davon ausgehen, dass die zweite Abhängigkeit nicht gilt, sodass sich die Beziehung wieder in BCNF befindet.

Renzo
quelle
1
Danke, Renzo. Ich schätze Ihre Erkenntnisse. Ich habe diesen Teil des Handbuchs gelesen. Ich habe auch Umanath und Scamells "Datenmodellierung und Datenbankdesign" von Anfang bis Ende gelesen, aber es wurden keine Situationen wie diese angesprochen. Nehmen Sie für akademische Zwecke an, dass item_number immer funktional jedes andere Attribut des Produkts bestimmt (wenn item_number vorhanden ist). Wenn wir zulassen, dass es null ist, kann item_number kein Kandidatenschlüssel sein. Als solches ist es ein Nicht-Primat-Attribut und daher verletzt Ihre Beziehung die 3. Normalform.
Harley
1
Ich bin nicht unbedingt darauf hindeutet , Anomalien wird auftreten. Ich brauche etwas Zeit, um darüber nachzudenken. Ich argumentiere vielmehr, dass die Produkttabelle in Ihrem Beispiel nicht auf 3NF normalisiert ist. Ich könnte mich natürlich irren. Vielleicht ist das alles akademisch. Weitere Einblicke von Ihnen wären sehr willkommen. Prost.
Harley
@Harley, ich habe der Antwort eine detailliertere Erklärung hinzugefügt, während die Beziehung normalisiert ist.
Renzo