Optionen zur Beseitigung von Nullable-Spalten von einem DB-Modell (um SQL des dreiwertigen Logik zu vermeiden)?

StackOverflow https://stackoverflow.com/questions/3079885

Frage

Einige Vor einiger Zeit, ich habe durch das Buch zu lesen SQL und relationale Theorie von CJ Datum . Der Autor ist bekannt für SQL der Kritik an dreiwertigen Logik (3VL). 1)

Der Autor macht einige Stärken, warum 3VL sollte in SQL vermieden werden, jedoch hat er nicht Umriss , wie ein Datenbankmodell aussehen würde, wenn Nullable-Spalten nicht erlaubt waren, . Ich habe ein bisschen auf diesen Gedanken und haben mit den folgenden Lösungen kommen. Wenn ich andere Gestaltungsmöglichkeiten verpasst haben, würde Ich mag über sie hören!

1) Datum Kritik an SQLs 3VL wiederum wurde auch kritisiert: siehe dieses Papier von Claude Rubinson (von CJ Datum der ursprünglichen Kritik enthält).


Beispiel Tabelle:

Als Beispiel nehmen Sie die folgende Tabelle, wo wir eine Nullable-Spalte (DateOfBirth):

#  +-------------------------------------------+
#  |                   People                  |
#  +------------+--------------+---------------+
#  |  PersonID  |  Name        |  DateOfBirth  |
#  +============+--------------+---------------+
#  |  1         |  Banana Man  |  NULL         |
#  +------------+--------------+---------------+

Option 1: emulieren NULL durch eine Fahne und ein Standardwert:

Statt die Spalte NULL festlegbaren machen, irgendein Standardwert angegeben (z.B. 1900-01-01). Eine zusätzliche BOOLEAN Spalte wird der Wert in DateOfBirth festlegen, ob einfach ignoriert werden soll oder ob es tatsächlich Daten enthält.

#  +------------------------------------------------------------------+
#  |                              People'                             |
#  +------------+--------------+----------------------+---------------+
#  |  PersonID  |  Name        |  IsDateOfBirthKnown  |  DateOfBirth  |
#  +============+--------------+----------------------+---------------+
#  |  1         |  Banana Man  |  FALSE               |  1900-01-01   |
#  +------------+--------------+----------------------+---------------+

Option 2: eine Spalte von -zulässige in eine separate Tabelle Drehen:

Die Nullable-Säule wird durch eine neue Tabelle (DatesOfBirth) ersetzt. Wenn ein Datensatz für diese Spalte keine Daten hat, wird es keinen Eintrag in der neuen Tabelle sein:

#  +---------------------------+ 1    0..1 +----------------------------+
#  |         People'           | <-------> |         DatesOfBirth       |
#  +------------+--------------+           +------------+---------------+
#  |  PersonID  |  Name        |           |  PersonID  |  DateOfBirth  |
#  +============+--------------+           +============+---------------+
#  |  1         |  Banana Man  |
#  +------------+--------------+

Während dies wie die bessere Lösung scheint, würde dies möglicherweise in vielen Tabellen, dass Bedarf für eine einzelne Abfrage verbunden werden. Da OUTER JOINs nicht erlaubt werden (weil sie NULL in der Ergebnismenge einführen würde), werden alle notwendigen Daten möglicherweise nicht mehr konnte mit nur einer einzigen Abfrage abgerufen werden wie zuvor.


Frage: Gibt es noch andere Möglichkeiten zur Beseitigung von NULL (und wenn ja, was sind sie)?

War es hilfreich?

Lösung

Ich habe seit Kollegen Hugh Darwen dieses Problem in einer exzellenten Präsentation diskutieren „wie Informationen Griff fehlt ohne NULL Verwendung“, die auf die dritte Manifest Website .

Seine Lösung ist eine Variante auf dem zweiten Ansatz. Es ist sechste Normalform, mit Tischen sowohl Geburtsdatum zu halten und Kennungen, wo es unbekannt ist:

#  +-----------------------------+ 1    0..1 +----------------------------+
#  |         People'             | <-------> |         DatesOfBirth       |
#  +------------+----------------+           +------------+---------------+
#  |  PersonID  |  Name          |           |  PersonID  |  DateOfBirth  |
#  +============+----------------+           +============+---------------+
#  |  1         |  Banana Man    |           ! 2          | 20-MAY-1991   |
#  |  2         |  Satsuma Girl  |           +------------+---------------+
#  +------------+----------------+
#                                  1    0..1 +------------+
#                                  <-------> | DobUnknown |
#                                            +------------+
#                                            |  PersonID  |
#                                            +============+
#                                            | 1          |
#                                            +------------+

von Menschen wählen dann verlangt, dass alle drei Tabellen verknüpft werden, einschließlich vorformulierten die unbekannten Geburtsdaten anzuzeigen.

Natürlich ist dies etwas theoretisch. Der Zustand von SQL wird in diesen Tagen immer noch nicht ausreichend, all dies zu handhaben fortgeschritten. Hugh Präsentation deckt diese Mängel. Eine Sache, die er erwähnt ist nicht ganz korrekt: einige Varianten von SQL unterstützt die Mehrfachzuordnung - zum Beispiel: Oracle INSERT ALL Syntax .

Andere Tipps

Ich empfehle Ihnen, gehen Sie für Ihre Wahl 2. Ich bin ziemlich sicher, Chris Datum würde auch, weil im Wesentlichen, was Sie tun, ist voll Normalisieren auf 6NF , die höchstmögliche Normalform, die Datum gemeinsam war verantwortlich einzuführen. Ich zweite empfahl die Darwen Papier auf die Verarbeitung von fehlenden Informationen.

  

Da Outer-Joins werden nicht erlaubt (weil sie NULL einführen würde   in der Ergebnismenge), alle notwendigen Daten könnten möglicherweise nicht mehr   geholt wird mit nur einer einzigen Abfrage wie zuvor.

... ist dies nicht der Fall ist, aber ich stimme mit der Frage der äußeren Verknüpfung nicht explizit in dem Darwen Papier erwähnt wird; es war das einzige, was ich will verlassen. Die explizite Antwort kann in einem anderen Datum des Buchs zu finden ...

Beachten Sie zunächst, dass Datum und Darwen eigene wirklich relationale Sprache Tutorial D hat aber man beitreten geben Sie den natürlichen Join zu sein. Die Begründung ist, dass nur ein Join-Typ tatsächlich benötigt wird.

Das Datum Buch, das ich erwähnt ist die ausgezeichnete SQL und relationale Theorie: Wie schreiben Accurate SQL-Code :

  

4.6: Eine Bemerkung zu Outer Join: „Relational gesprochen, [Outer Join ist] ein   Art der Schrotflinte Ehe: Es zwingt Tabellen in eine Art Gewerkschaft ja, ich   Bedeuten Union nicht beitreten, selbst wenn die Tabellen in Frage scheitern   entsprechen den üblichen Anforderungen für die Vereinigung ... Es tut dies, in   Effekt, durch Auffüllen eines oder beide der Tabellen mit NULL-Werte, bevor Sie   die Vereinigung, wodurch sie zu diesen üblichen Anforderungen entsprechen   Letztendlich. Aber es gibt keinen Grund, warum das Polster nicht getan werden soll   mit dem richtigen Werten anstelle von NULL-Werten

Arbeiten mit dem Beispiel und den Standardwert ‚1900-01-01‘ als ‚padding‘, die Alternative zu Outer-Joins könnte wie folgt aussehen:

SELECT p.PersonID, p.Name, b.DateOfBirth
  FROM Person AS p
       INNER JOIN BirthDate AS b
          ON p.PersonID = b.PersonID
UNION
SELECT p.PersonID, p.Name, '1900-01-01' AS DateOfBirth
  FROM Person AS p
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM BirthDate AS b
                    WHERE p.PersonID = b.PersonID
                  );

Darwen Papier Proses zwei explizite Tabellen, sagen BirthDate und BirthDateKnown, aber die SQL würde nicht viel anders sein, z.B. ein halb beitreten zu BirthDateKnown anstelle des halb Unterschied zu BirthDate oben.

Beachten Sie die oben genannten Verwendungen JOIN und INNER JOIN nur, weil Standard-SQL-92 NATURAL JOIN und UNION CORRESPONDING sind nicht weit verbreitet in der realen Leben SQL Produkte umgesetzt (kann nicht ein Zitat finden, aber IIRC Darwen war weitgehend verantwortlich für die beiden letzteren in die Standard-Herstellung ).

Ferner ist zu beachten die obige Syntax sieht langatmige nur weil SQL im Allgemeinen ist langatmig. In der reinen relationalen Algebra ist es eher wie (Pseudo-Code):

Person JOIN BirthDate UNION Person NOT MATCHING BirthDate ADD '1900-01-01' AS DateOfBirth;

Ich habe es nicht gelesen, aber es gibt einen Artikel mit dem Titel Wie Fehlende Informationen Handle Mit S-by-C auf der der Drittes Manifest Website, die von Hugh Darwen und CJ Datum laufen gelassen. Dies wird von C. J. Datum geschrieben, aber ich würde davon ausgehen, dass es eines des Artikels auf dieser Website, da es seine Meinung wahrscheinlich ähnlich ist.

Eine Alternative kann das Entity-Attribut-Wert- Modell:

 entity  attribute    value
 1       name         Banana Man
 1       birthdate    1968-06-20

Wenn das Geburtsdatum unbekannt war, würden Sie einfach weglassen die entsprechende Zeile.

Option 3: Onus auf dem Aufzeichnungs Schreiber:

CREATE TABLE Person
(
  PersonId int PRIMARY KEY IDENTITY(1,1),
  Name nvarchar(100) NOT NULL,
  DateOfBirth datetime NOT NULL
)

contort Warum ein Modell null Darstellung zu ermöglichen, wenn Ihr Ziel ist es, sie zu beseitigen?

Sie können auch null in der Ausgabe beseitigen, indem Sie COALESCE .

SELECT personid  /*primary key, will never be null here*/
       , COALESCE(name, 'no name') as name
       , COALESCE(birthdate,'no date') as birthdate
FROM people

Nicht alle Datenbanken unterstützen COALESCE, aber fast alle eine Ersatzoption aufgerufen haben
IFNULL(arg1, arg2) oder etwas simular, die das gleiche tun (aber nur für 2 Argumente) .

Eine Option ist explizit Optionstypen verwenden , analog zu Haskells Maybe Funktors.

Leider haben viele bestehenden SQL-Implementierungen schlechte Unterstützung für benutzerdefinierte algebraische Datentypen und noch ärmere Unterstützung für benutzerdefinierte Typkonstruktoren, dass Sie das wirklich tun müssen, um sauber.

Diese wieder eine Art von „null“ nur für jene Attribute, wo Sie ausdrücklich darum bitten, aber ohne null silly dreiwertigen Logik. Nothing == Nothing ist True, nicht unknown oder null.

Unterstützung für benutzerdefinierte algebraische Typen hilft auch, wenn es ein paar Gründe für die fehlenden Informationen sind zum Beispiel eine Datenbank Äquivalent des folgenden Haskell Typ eine gute Lösung für die offensichtliche Anwendung wäre:

data EmploymentStatus = Employed EmployerID | Unemployed | Unknown

(Natürlich eine Datenbank dieser Unterstützung würde auch die mehr kompliziert als üblich Einschränkung Fremdschlüssel müssen unterstützen, die mit ihm kommt.)

Kurz dies, ich bin einverstanden mit APC 's und onedaywhen 's Antworten zu 6NF.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top