primaria llave foreign ejemplos developer crear compuesta clave database database-design

database - foreign - crear llave primaria oracle



¿Qué pasa con las columnas que aceptan nulos en las claves primarias compuestas? (6)

ORACLE no permite valores NULL en ninguna de las columnas que comprenden una clave principal. Parece que lo mismo es cierto para la mayoría de los otros sistemas de "nivel empresarial".

Al mismo tiempo, la mayoría de los sistemas también permiten contraints únicos en columnas que aceptan nulos.

¿Por qué las restricciones únicas pueden tener valores NULL pero las claves primarias no? ¿Hay una razón lógica fundamental para esto, o es más una limitación técnica?


Fundamentalmente, nada está mal con un NULL en una clave primaria de múltiples columnas. Pero tener una tiene implicaciones que probablemente el diseñador no pretendía, y es por eso que muchos sistemas arrojan un error cuando intentas esto.

Considere el caso de las versiones de módulo / paquete almacenadas como una serie de campos:

CREATE TABLE module (name varchar(20) PRIMARY KEY, description text DEFAULT '''' NOT NULL); CREATE TABLE version (module varchar(20) REFERENCES module, major integer NOT NULL, minor integer DEFAULT 0 NOT NULL, patch integer DEFAULT 0 NOT NULL, release integer DEFAULT 1 NOT NULL, ext varchar(20), notes text DEFAULT '''' NOT NULL, PRIMARY KEY (module, major, minor, patch, release, ext));

Los primeros 5 elementos de la clave principal son partes regularmente definidas de una versión comercial, pero algunos paquetes tienen una extensión personalizada que generalmente no es un número entero (como "rc-foo" o "vainilla" o "beta" o cualquier otra cosa para la que Quien cuatro campos es insuficiente podría soñar despierto. Si un paquete no tiene una extensión, entonces es NULO en el modelo anterior, y no se dañará dejando las cosas de esa manera.

Pero, ¿qué es un NULL? Se supone que representa una falta de información, un desconocido. Dicho esto, quizás esto tenga más sentido:

CREATE TABLE version (module varchar(20) REFERENCES module, major integer NOT NULL, minor integer DEFAULT 0 NOT NULL, patch integer DEFAULT 0 NOT NULL, release integer DEFAULT 1 NOT NULL, ext varchar(20) DEFAULT '''' NOT NULL, notes text DEFAULT '''' NOT NULL, PRIMARY KEY (module, major, minor, patch, release, ext));

En esta versión, la parte "ext" de la tupla NO ES NULA, sino que está por defecto en una cadena vacía, que es semánticamente (y prácticamente) diferente de un NULO. A NULL es un desconocido, mientras que una cadena vacía es una definición deliberada de "algo que no está presente". En otras palabras, "vacío" y "nulo" son cosas diferentes. Es la diferencia entre "Aquí no tengo ningún valor" y "No sé cuál es el valor aquí".

Cuando registra un paquete que carece de una extensión de versión, sabe que carece de una extensión, por lo que una cadena vacía es realmente el valor correcto. Un NULL solo sería correcto si no supiera si tiene una extensión o no. Esta situación es más fácil de tratar en sistemas donde los valores de cadena son la norma, porque no hay forma de representar un "entero vacío" que no sea insertar 0 o 1, que terminará enrollado en cualquier comparación hecha más adelante (que tiene sus propias implicaciones).

Incidentalmente, ambas formas son válidas en Postgres (ya que estamos discutiendo RDMBS "empresariales"), pero los resultados de comparación pueden variar bastante cuando se arroja un NULL a la mezcla, porque NULL == "no sé", por lo que todos los resultados de una comparación que implica un NULL wind up son NULL ya que no se puede saber algo desconocido. Así que esto puede ser una fuente de errores sutiles al ordenar, comparar, etc. Postgres asume que eres un adulto y puede tomar esta decisión por ti mismo. Oracle y DB2 suponen que no se dio cuenta de que estaba haciendo algo tonto y arrojó un error. Esto suele ser lo correcto, pero no siempre, es posible que en realidad no sepa y tenga un NULL en algunos casos y, por lo tanto, dejar una fila con un elemento desconocido contra el cual las comparaciones significativas son imposibles es el comportamiento correcto.

En cualquier caso, debe esforzarse por eliminar el número de campos NULL que permite en todo el esquema y doblemente cuando se trata de campos que forman parte de una clave principal. En la gran mayoría de los casos, la presencia de columnas NULL es indicativa de un diseño de esquema no normalizado (en lugar de deliberadamente desnormalizado) y debe pensarse mucho antes de ser aceptado.


La respuesta de Tony Andrews es decente. Pero la verdadera respuesta es que esta ha sido una convención utilizada por la comunidad de bases de datos relacionales y NO es una necesidad. Tal vez es una buena convención, tal vez no.

Comparando cualquier cosa con los resultados NULL en DESCONOCIDO (tercer valor de verdad). Entonces, como se ha sugerido con nulos, toda la sabiduría tradicional concerniente a la igualdad sale por la ventana. Bueno, así es como parece a primera vista.

Pero no creo que esto sea necesariamente así, e incluso las bases de datos SQL no creen que NULL destruya todas las posibilidades de comparación.

Ejecute en su base de datos la consulta SELECT * FROM VALUES (NULL) UNION SELECT * FROM VALUES (NULL)

Lo que ves es solo una tupla con un atributo que tiene el valor NULO. Entonces la unión reconoció aquí los dos valores NULL como iguales.

Al comparar una clave compuesta que tiene 3 componentes con una tupla con 3 atributos (1, 3, NULO) = (1, 3, NULO) <=> 1 = 1 Y 3 = 3 Y NULO = NULO El resultado de esto es DESCONOCIDO .

Pero podríamos definir un nuevo tipo de operador de comparación, por ejemplo. ==. X == Y <=> X = Y O (X ES NULO E Y ES NULO)

Tener este tipo de operador de igualdad haría las claves compuestas con componentes nulos o claves no compuestas con valor nulo sin problemas.


Las claves principales son para identificar filas de manera única. Esto se hace comparando todas las partes de una clave con la entrada.

Por definición, NULL no puede ser parte de una comparación exitosa. Incluso una comparación consigo misma ( NULL = NULL ) fallará. Esto significa que una clave que contenga NULL no funcionaría.

Additonally, NULL está permitido en una clave externa, para marcar una relación opcional. (*) Permitirlo en el PK también rompería esto.

(*) Una palabra de advertencia: tener claves foráneas que aceptan nulos no es un diseño de base de datos relacional limpio.

Si hay dos entidades A y B donde A puede estar opcionalmente relacionado con B , la solución limpia es crear una tabla de resolución (digamos AB ). Esa tabla vincularía A con B : si hay una relación, entonces contendría un registro, si no hubiera, entonces no lo haría.


NULL == NULL -> falso (al menos en DBMS)

Por lo tanto, no podrá recuperar ninguna relación utilizando un valor NULL incluso con columnas adicionales con valores reales.


Todavía creo que esto es una falla fundamental / funcional provocada por un tecnicismo. Si tiene un campo opcional mediante el cual puede identificar a un cliente, ahora tiene que hackear un valor ficticio en él, simplemente porque NULL! = NULL, no particularmente elegante, pero es un "estándar de la industria".


Una clave principal define un identificador único para cada fila en una tabla: cuando una tabla tiene una clave principal, usted tiene una manera segura de seleccionar cualquier fila de la misma.

Una restricción única no identifica necesariamente cada fila; solo especifica que si una fila tiene valores en sus columnas, entonces deben ser únicos. Esto no es suficiente para identificar de forma única cada fila, que es lo que debe hacer una clave principal.