Estoy desarrollando una base de datos SQL Server 2012 y tengo una pregunta sobre una relación de uno a cero o uno.
Tengo dos mesas Codes
y HelperCodes
. Un código podría tener cero o un código auxiliar. Este es el script sql para crear estas dos tablas y sus relaciones:
CREATE TABLE [dbo].[Code]
(
[Id] NVARCHAR(20) NOT NULL,
[Level] TINYINT NOT NULL,
[CommissioningFlag] TINYINT NOT NULL,
[SentToRanger] BIT NOT NULL DEFAULT 0,
[LastChange] NVARCHAR(50) NOT NULL,
[UserName] NVARCHAR(50) NOT NULL,
[Source] NVARCHAR(50) NOT NULL,
[Reason] NVARCHAR(200) NULL,
[HelperCodeId] NVARCHAR(20) NULL,
CONSTRAINT [PK_Code] PRIMARY KEY CLUSTERED
(
[Id] ASC
),
CONSTRAINT [FK_Code_LevelConfiguration]
FOREIGN KEY ([Level])
REFERENCES [dbo].[LevelConfiguration] ([Level]),
CONSTRAINT [FK_Code_HelperCode]
FOREIGN KEY ([HelperCodeId])
REFERENCES [dbo].[HelperCode] ([HelperCodeId])
)
CREATE TABLE [dbo].[HelperCode]
(
[HelperCodeId] NVARCHAR(20) NOT NULL,
[Level] TINYINT NOT NULL,
[CommissioningFlag] TINYINT NOT NULL,
[LastChange] NVARCHAR(50) NOT NULL,
CONSTRAINT [PK_HelperCode] PRIMARY KEY CLUSTERED
(
[HelperCodeId] ASC
),
CONSTRAINT [FK_HelperCode_LevelConfiguration]
FOREIGN KEY ([Level])
REFERENCES [dbo].[LevelConfiguration] ([Level])
)
¿Es eso correcto?
Un código y un HelperCode son entidades diferentes. Un HelperCode puede ser usado (ningún Código lo hace referencia) o usado (solo un Código lo hace referencia).
Quizás Code.HelperCodeId debe ser parte de la clave primaria de la tabla de códigos. Pero no estoy seguro de si una columna nula podría ser parte de una primaria. Al hacer esto, quiero evitar que dos o más códigos hagan referencia al mismo HelperCode.
database-design
sql-server-2012
VansFannel
fuente
fuente
HelperCodeId
ser parte de la PK? ¿Es, por casualidad, porque quiere evitar que dos o más Códigos hagan referencia al mismo Código de ayuda?HelperCodeId
columna como Única.Respuestas:
Para responder la pregunta en el título, no, todas las columnas primarias deben ser
NOT NULL
.Pero sin alterar el diseño de las tablas, puede agregar un índice filtrado en la
Code (HelperCodeId)
columna:El filtro (
WHERE HelperCodeId IS NOT NULL
) es necesario debido a la forma en que SQL-Server trata los valores nulos en restricciones únicas e índices únicos. Sin el filtro, SQL-Server no permitiría más de una fila conNULL
inHelperCodeId
.Un diseño alternativo se retire la
HelperCodeId
deCode
y añadir una tercera tabla que almacenará losCode
-HelperCode
las relaciones. La relación entre las dos entidades parece ser Cero o Uno a Cero o Uno (tanto un Código puede no tener HelperCode como un HelperCode no puede ser usado por ningún Código):HelperCode
permanece sin cambios:La tabla adicional tendrá dos
UNIQUE
restricciones (o una primaria y una única) para garantizar que cada Código esté relacionado con (máximo) un Código de Helper y cada Código de Helper esté relacionado con (máximo) un Código. Ambas columnas seríanNOT NULL
:fuente
Intente usar una restricción única en su lugar. Supuestamente, el estándar ANSI declaró que los valores nulos como clave principal no eran válidos, pero nunca he visto el estándar y no deseo comprarlo para verificar esto.
No tener claves nulas parece ser una de esas cosas en las que los desarrolladores tienen una creencia muy dura de una forma u otra. Prefiero usarlos porque me resulta útil para las tablas de búsqueda que contienen información sobre herramientas y datos relacionados para cuadros combinados que no se han rellenado.
Me enseñaron que el valor nulo indica que una variable nunca se ha establecido y el valor vacío indica que el valor se ha establecido en el pasado. Por supuesto, esto depende del desarrollador para definir la aplicación, pero me parece absurdo permitir claves primarias vacías pero no claves primarias nulas.
fuente