¿Una mala práctica de clave externa anulable?

114

Supongamos que tiene una tabla Pedidos con una clave externa a un ID de cliente. Ahora, suponga que desea agregar un pedido sin un ID de cliente, (si eso debería ser posible es otra pregunta), tendría que hacer que la clave externa sea NULL ... ¿Es una mala práctica o prefiere trabajar con una tabla de enlaces entre Pedidos y Clientes? Aunque la relación es de 1 an, una tabla de vínculos la convertiría en n an. Por otro lado, con una tabla de enlaces, ya no tengo esos NULLS ...

En realidad, no habrá muchos NULL en la base de datos, porque un registro con una clave externa a NULL es solo temporalmente hasta que se agrega un cliente para el pedido.

(En mi caso no es un Pedido y un Cliente).

EDITAR: ¿Qué pasa con un Cliente no asignado para vincular?

Lieven Cardoen
fuente
9
Ese ES uno de los propósitos principales de tener NULL disponibles en un esquema de base de datos. Además, es por eso que puede declarar campos NULL o NOT NULL, para que se puedan cumplir los requisitos específicos de su esquema.
Gahooa
7
Inicialmente leí la pregunta como claves primarias anulables , y estaba a punto de intervenir con algunos consejos fuertes ... :-)
Andrzej Doyle

Respuestas:

51

Tener la tabla de enlaces es probablemente una mejor opción. Al menos no viola la normalización BCNF (forma normal de Boyce-Codd). sin embargo, preferiría ser pragmático. Si tiene muy pocos de estos valores nulos y son solo temporales, creo que debería omitir la tabla de enlaces, ya que solo agrega complejidad al esquema.

En otros comentarios; el uso de una tabla de enlaces no necesariamente lo convierte en n an, si en la tabla de enlaces usa la clave externa que apunta a su tabla de pedidos como la clave principal en esa tabla de enlaces, la relación sigue siendo 1..n. Solo puede haber una entrada en esa tabla de enlaces por pedido.

Patrik Hägne
fuente
2
source__destination_link o SourceDestination
Svisstack
7
Me interesaría escuchar acerca de una situación en la que tener una tabla de enlaces es mejor, nunca me he encontrado con una situación en la que hubiera mejorado el flujo del proceso de alguna manera.
Reimius
5
Como se señaló en mi respuesta, sería pragmático en este caso específico y no usaría una tabla de enlaces. Estoy seguro de que las formas normales no se inventaron para mejorar el flujo del proceso, sino para garantizar la coherencia y evitar la redundancia. Sin embargo, es una discusión muy general, creo que debe analizarse caso por caso.
Patrik Hägne
110

No No hay nada de malo con los FK que aceptan valores NULL. Esto es común cuando la entidad a la que apunta FK está en una relación (de cero o uno) a (1 o muchos) con la tabla de referencia de la clave principal.

Un ejemplo podría ser si tuviera una dirección física y un atributo (columna) de dirección postal en una tabla, con FK en una tabla de direcciones. Puede hacer que la dirección física sea anulable para manejar cuando la entidad solo tenga un apartado de correos (dirección postal) y la dirección postal sea anulable para manejar cuando la dirección postal sea la misma que la dirección física (o no).

Charles Bretana
fuente
39

Las columnas que aceptan valores NULL pueden estar en 1NF a 5NF, pero no en 6NF según lo que he leído.

Solo si sabes mejor que Chris Date "lo que realmente significa la primera forma normal". Si xey son ambos anulables, y de hecho en alguna fila xey son ambos null, entonces WHERE x=yno cede true. Esto prueba más allá de toda duda razonable que nulo no es un valor (porque cualquier valor real es siempre igual a sí mismo). Y dado que la RM prescribe que "debe haber un valor en cada celda de una tabla", cualquier cosa que posiblemente contenga nulos, no es una cosa relacional, y por lo tanto la cuestión de 1NF ni siquiera surge.

He oído decir que las columnas que aceptan valores NULL en general rompen el primer grado de normalización.

Consulte más arriba la sólida razón que subyace a ese argumento.

Pero en la práctica es muy práctico.

Solo si eres inmune a los dolores de cabeza que suele provocar en todo el resto del mundo. Uno de esos dolores de cabeza (y es solo uno menor, en comparación con otros nullfenómenos) es el hecho de que WHERE x=yen SQL realmente significaWHERE x is not null and y is not null and x=y , pero que la mayoría de los programadores simplemente no son conscientes de ese hecho y simplemente lo leen. A veces sin ningún daño, otras veces no.

De hecho, las columnas que aceptan valores NULL violan una de las reglas de diseño de bases de datos más fundamentales: no combine elementos de información distintos en una columna. Los nulos hacen exactamente eso porque combinan el valor booleano "este campo está / no está realmente presente" con el valor real.

Erwin Smout
fuente
18
+1 para "DONDE x no es nulo e y no es nulo y x = y". No estaba consciente de eso.
RobM
1
Argumentos y ejemplos muy bien presentados.
pedz
1
Un problema. Cuando el valor "no existe" (que ES un escenario del mundo real), y el atributo de la base de datos no permite valores nulos, cualquier valor que esté en el atributo es INCORRECTO. En cuanto a los dolores de cabeza, recuerde, KISS, no solo significa mantenerlo simple, significa mantenerlo lo más simple posible, pero no más simple. Si el "modelo relacional" requiere un resultado estúpido e irreal, entonces, ¿quizás las reglas necesitan expandirse para manejar los datos necesarios del mundo real?
Charles Bretana
1
Se ha demostrado que una lógica de tres valores conduce a la necesidad de una lógica de cuatro valores, y eso conduce a la necesidad de una lógica de cinco valores, etc. etc. La lógica de dos valores es suficiente, pero las estructuras de datos que obtenemos cuando aplicarlo hace que "lo más simple posible" sea mucho menos simple que "tan simple como nos gustaría".
Erwin Smout
2
Chris Date, Logic & Databases, Capítulo 6, "Por qué la lógica DBMS relacional no debe tener muchos valores", pág. 145. La lista de referencias a ese capítulo también debería ser interesante, especialmente las que involucran a McGoveran.
Erwin Smout
13

No veo nada de malo en que sea solo una relación n-1 opcional que se representará con un nulo en la clave externa. De lo contrario, si coloca su tabla de enlaces, tendrá que gestionar que no se convierta en una relación nn, lo que provocará aún más problemas.

pedromarce
fuente
2
En realidad, es una relación 0-N, no una relación 1-N opcional. Pero estoy de acuerdo contigo.
Eric J.
5
¿Gestionar? ¡Es una restricción ÚNICA simple en el lado 0 a 1!
wqw
2
Sí, es una restricción ÚNICA, pero también tendrá que lidiar con posibles excepciones más adelante en su código debido a esa restricción ...
pedromarce
4

Las relaciones opcionales son definitivamente posibles en el modelo relacional.

Puede utilizar valores nulos para expresar la ausencia de una relación. Son convenientes, pero le causarán los mismos dolores de cabeza que los nulos le causan en otros lugares. Un lugar donde no causan ningún problema son las uniones. Las filas que tienen un valor nulo en la clave externa no coinciden con ninguna fila de la tabla a la que se hace referencia. Así que abandonan una unión interna. Si realiza uniones externas, de todos modos tendrá que lidiar con nulos.

Si realmente desea evitar nulos (sexta forma normal), puede descomponer la tabla. Una de las dos tablas descompuestas tiene dos columnas de clave externa. Una es la clave externa opcional que tiene y la otra es una clave externa que hace referencia a la clave principal de la tabla original. Ahora tiene que usar restricciones para evitar que la relación se convierta en muchos a muchos, si quiere evitar eso.

Walter Mitty
fuente
2

Usar NULL sería una buena manera de limpiar pedidos incompletos:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Lo anterior mostraría pedidos de más de 15 minutos sin una identificación de cliente relacionada.

matpie
fuente
1

Si solo está agregando el pedido temporalmente sin identificación de cliente hasta que se defina un cliente, ¿no sería más sencillo agregar el cliente y el pedido en una sola transacción, eliminando así la necesidad de la entrada de clave externa NULL y evitando cualquier restricción o desencadenante? has configurado para ser violado?

Normalmente esta situación se presenta en aplicaciones web donde se detalla el pedido antes de que el cliente defina quién es. Y en esas situaciones, el pedido se mantiene en el estado del servidor o en una cookie hasta que se proporciona todo el estado necesario para un pedido completo, momento en el que el pedido se conserva en la base de datos.

Las claves externas NULL están bien para cosas como direcciones, como se mencionó anteriormente. Pero un campo de cliente NULO no tiene sentido para un pedido y debe estar limitado.

Mark Green
fuente
El pedido-cliente fue un ejemplo. En mi aplicación es idd más como direcciones. No pude encontrar de inmediato un ejemplo que fuera correcto en todo momento. Gracias.
Lieven Cardoen
1
Este podría ser un escenario válido si la base de datos se utiliza para almacenar artículos en un carrito de compras, donde el carrito de compras no pertenece a un usuario registrado.
Johnie Karr
1

Siempre puede agregar una fila artificial a su tabla de Clientes, algo como Id = -1 y CustomerName = 'Desconocido' y luego, en los casos en que normalmente establecería su CustomerId en Order NULL, configúrelo en -1.

Esto le permite no tener FK que aceptan valores NULL, pero aún así representar la falta de datos de manera adecuada (y evitará que los usuarios posteriores no sepan cómo lidiar con los NULL).

Stephen S.
fuente
Solo para agregar a esto, recuerde que los NULLS no se almacenan en un índice (en Oracle), por lo que esto significa que omitir la tabla de enlaces y buscar el FK que acepta valores NULL tendría sentido, en términos de rendimiento. La otra cosa de la que podría depender es si desea almacenar algo más en esta tabla de enlaces, por ejemplo, ¿QUIÉN hizo el enlace y cuándo? ¿El enlace ahora está inactivo / eliminado (pero una vez lo estuvo?)
Worthy7
Esta es una mala idea. Si tiene una clave externa configurada y los datos a los que apunta se eliminan más tarde, no obtendrá la excepción de clave externa y ahora sus datos no tienen sentido. Peor aún, si luego se asigna algo más a esa clave, está apuntando al cliente completamente equivocado
IcedDante
0

Los FK que aceptan valores NULL para relaciones opcionales de varios a uno están totalmente bien.

Henning
fuente
-1

He escuchado argumentar que las columnas que aceptan valores NULL en general rompen el primer grado de normalización. Pero en la práctica es muy práctico.

Bryan McLemore
fuente
3
Las columnas que aceptan valores NULL pueden estar en 1NF a 5NF, pero no en 6NF según lo que he leído.
Walter Mitty
-1

Sí, hay algo mal. No es una clave externa si es anulable. Su diseño de base de datos por código. Quizás hagas un enlace cero a no asignado. o "Sin asignar" si estás usando un carácter col. Mantenga la integridad de sus datos al 100%.

danny117
fuente