Las opciones para la eliminación de columnas anulables de un modelo de base de datos (con el fin de evitar la lógica trivalente de SQL)?

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

Pregunta

Hace algún tiempo, he estado leyendo a través del libro SQL y relacional Teoría por CJ Fecha . El autor es bien conocido por criticar lógica trivalente de SQL (3VL). 1)

El autor hace algunos puntos fuertes acerca de por qué 3VL debe evitarse en SQL, sin embargo no lo hace esquema cómo un modelo de base de datos se vería como si las columnas con valores nulos no se les permitió . He pensado en esto por un poco y debido haber establecido las siguientes soluciones. Si me perdí otras opciones de diseño, me gustaría oír hablar de ellos!

1) La crítica de Fecha de 3VL de SQL a su vez ha sido criticado también: consulte este documento por Claude Rubinson (incluye la crítica original de CJ Date).


Ejemplo tabla:

A modo de ejemplo, tomar la siguiente tabla en la que tenemos una columna anulable (DateOfBirth):

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

Opción 1: Emulación de NULL a través de una bandera y un valor por defecto:

En lugar de hacer la anulable columna, se especifica ningún valor predeterminado (por ejemplo 1900-01-01). Una columna adicional BOOLEAN especificará si el valor en DateOfBirth simplemente debe ser ignorada o si en realidad contiene los datos.

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

Opción 2: Convertir una columna anulable en una tabla separada:

La columna anulable se sustituye por una nueva tabla (DatesOfBirth). Si un registro no tiene datos para esa columna, no habrá un registro en la nueva tabla:

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

Si bien esto parece la mejor solución, esto podría posiblemente resultar en muchas mesas que necesitan ser unidas por una sola consulta. Dado que no se les permitirá OUTER JOINs (porque introducirían NULL en el conjunto de resultados), todos los datos necesarios podrían posiblemente ya no se encontraron con sólo una única consulta que antes.


Pregunta: ¿Hay otras opciones para eliminar NULL (y si es así, ¿cuáles son)?

¿Fue útil?

Solución

El colega de I Fecha sierra Hugh Darwen discutir esta cuestión en una excelente presentación "Cómo manejar información que falta sin utilizar NULL", que está disponible en la página web tercer manifiesto .

Su solución es una variante en su segundo enfoque. Es la sexta forma normal, con mesas para sostener tanto Fecha de nacimiento y los identificadores, donde se desconoce:

#  +-----------------------------+ 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          |
#                                            +------------+

Selección de Personas requiere entonces unirse a las tres tablas, incluyendo texto modelo para indicar las fechas de nacimiento desconocido.

Por supuesto, esto es algo teórico. El estado de SQL en estos días todavía no está suficientemente avanzada como para manejar todo esto. La presentación de Hugh cubre estas deficiencias. Una cosa que él menciona no es del todo correcta: algunas versiones de SQL hacen de soporte asignación múltiple - por ejemplo, de Oracle insertar todos sintaxis .

Otros consejos

recomiendo que vaya para su opción 2. Estoy bastante seguro de Chris Fecha también lo haría, porque en esencia lo que está haciendo es totalmente normalización a 6NF , la más alta posible, que forma normal Fecha estaba en forma conjunta responsable de la introducción . Lo segundo es la cantidad recomendada de de Darwen papel en el manejo de la información que falta.

  

Desde combinaciones externas no se le permitirá (porque introducirían NULL   en el conjunto de resultados), todos los datos necesarios podría posiblemente ya no se   se encontraron con sólo una única consulta que antes.

... este no es el caso, pero estoy de acuerdo el tema de la combinación externa no se menciona explícitamente en el documento Darwen; que era la única cosa que me dejó. La respuesta explícita se puede encontrar en otro del libro de fecha ...

En primer lugar, cabe destacar que la fecha y la propia lengua verdaderamente relacional de Darwen Tutorial D tiene pero el tipo de combinación es la reunión natural. La justificación es que sólo uno es realmente necesario unirse tipo.

El libro Fecha he aludido es el excelente SQL y relacional Teoría: ¿Cómo escribir código SQL precisa :

  

4.6: una observación en combinación externa: "Relacionalmente hablando, [combinación externa es] una   tipo de matrimonio forzado: Obliga a tablas en una especie de unión-sí,   hacer la unión media, no unirse, incluso cuando las tablas en cuestión no consiguen   ajustarse a los requisitos habituales para la unión ... Lo hace, en   efecto, por uno o ambos de relleno de las mesas con nulos antes de hacer   la unión, con lo que se adecuen a los requisitos habituales   después de todo. Pero no hay ninguna razón por la que el relleno no se debe hacer   con los valores apropiados en lugar de valores nulos

Usando su ejemplo y valor por defecto '1900-01-01' como 'padding', la alternativa a la combinación externa podría tener este aspecto:

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
                  );

El artículo de Darwen PROSES dos tablas explícitas, dicen BirthDate y BirthDateKnown, pero el SQL no sería muy diferente, por ejemplo, Un semi unen a BirthDateKnown en lugar de la diferencia semi a BirthDate anteriormente.

Tenga en cuenta los usos y JOIN INNER JOIN anteriormente sólo porque estándar SQL-92 y NATURAL JOIN UNION CORRESPONDING no se aplican ampliamente en productos de SQL de la vida real (no puede encontrar una citación, pero IIRC Darwen fue en gran parte responsable de estos dos últimos por lo que es en la Norma ).

nota además de las miradas sintaxis anterior de largo aliento sólo porque SQL en general es largo aliento. En el álgebra relacional pura es más como (pseudo código):

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

Yo no lo he leído, pero no hay un artículo llamado Cómo manejar Falta información del uso de S-por-C en el sitio web tercer manifiesto que está dirigido por Hugh Darwen y CJ Date. Esto no está escrito por C. J. Fecha, pero me gustaría suponer que ya que es uno de los artículos sobre ese sitio web es probable que sea similar a sus opiniones.

Una alternativa puede ser la href="http://en.wikipedia.org/wiki/Entity-attribute-value_model" rel="nofollow noreferrer"> entidad-atributo-valor modelo

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

Si la fecha de nacimiento era desconocido, usted acaba omite su fila.

Opción 3: responsabilidad en el escritor de registro:

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

¿Por qué contorsionarse un modelo que permita la representación nula cuando su objetivo es eliminarlos?

Puede eliminar null en la salida, así mediante el uso de COALESCE .

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

No todas las bases de apoyo COALESCE, pero casi todos tienen una opción de reserva llamado
IFNULL(arg1, arg2) o algo simular que va a hacer el mismo (pero sólo para 2 argumentos) .

Una opción es utilizar explícitas href="http://en.wikipedia.org/wiki/Option_type" , análogos a funtor Maybe de Haskell.

Por desgracia, una gran cantidad de implementaciones SQL existentes tienen poco apoyo para tipos de datos definidos por el usuario algebraica y aún más pobre apoyo a constructores de tipos definidos por el usuario que realmente se necesita para hacer esto limpiamente.

Este se recupera una especie de "nulo" sólo para aquellos atributos en el que pedirlo explícitamente, pero sin tonta lógica trivalente de null. Nothing == Nothing es True, no unknown o null.

El apoyo a los tipos definidos por el usuario algebraicas también ayuda cuando hay algunas razones de falta de información, por ejemplo, un equivalente de base de datos de los siguientes tipos de Haskell sería una buena solución para la aplicación obvia:

data EmploymentStatus = Employed EmployerID | Unemployed | Unknown

(Por supuesto, una base de datos que apoya esta también tendría que soportar la restricción de clave externa más complicado de lo habitual, que viene con él.)

A falta de esto, estoy de acuerdo con APC 's y onedaywhen 's respuestas sobre 6NF.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top