viernes, 4 de diciembre de 2015

Receta T-SQL No. 3-6: Forzar la Unicidad de una Columna con NULL

Índice

1. Introducción
2. Palabras Clave
3. Problmea
4. Solución
5. Discusión de la Solución
5.1 Índice único -unique index-
6. Práctica: Código T-SQL
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Esta nueva receta Transact-SQL enseña a utilizar un mecanismo para asegurar la unicidad de una columna que admita NULL. Se demuestra en primera instancia que un índice único -unique index- evita duplicados tanto de valores concretos para un tipo de dato específico como de valores desconocidos NULL. Esto es posible a través de la creación de un índice único nonclustered, el cual permite la unicidad de valores concretos y multiplicidad o asignación de NULL a múltiples registros para el mismo campo.

2. Palabras Clave

  • Índice
  • Índice único
  • Multiplicidad
  • Unicidad
  • Nonclustered index

3. Problema

Permitir que una columna de una tabla pueda contener valores concretos únicos de un tipo de dato específico. Además que se permitan múltiples valores NULL.

4. Solución

Usar un índice no-agrupado o nonclustered para el campo que debe cumplir el requerimiento de unicidad para valores concretos y multiplicidad para valores no conocidos o NULL.

5. Discusión de la Solución

5.1 Índice único -unique index-

Un índice único (o unique index) es un tipo de índice que garantiza la unicidad o no duplicado de valores para un campo o columna llave ("Create Unique Indexes", 2015). Además, este tipo de índice puede involucrar varias columnas. Por ejemplo se puede crear un índice para un número de teléfono para un requerimiento de negocio que especifique que cada cliente debe tener uno o más números de teléfono distintos a cualquiera de los demás clientes.

Lo anterior también aplica para una combinación de columnas como PrimerNombre, SegundoNombre, Apellidos. En el índice único no puede existir más de un registro que tenga la misma combinación de primer nombre, segundo nombre y apellidos.

Otro propósito interesante de este clase de índice es garantizar la integridad de datos sobre la o las columnas que forman parte del índice. Además, como se manifiesta en "Create Unique Indexes" (2015), un índice único facilita información extra para el optimizador de consultas de SQL Server.

6. Práctica: Código T-SQL

Creación de tabla Producto:

CREATE TABLE Producto
(
IdProducto INT NOT NULL
CONSTRAINT PK_Producto PRIMARY KEY CLUSTERED,
NombreProducto NVARCHAR(50) NOT NULL,
NombreClave NVARCHAR(50)
);

A coninuación se ha de crear el índice único nonclustered:

CREATE UNIQUE INDEX UX_Producto_NombreClave ON Producto(NombreClave);

A partir de aquí se prueba con la inserción de registros en la misma tabla:

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (1, 'Producto #1', 'Adven');

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (2, 'Producto #2', 'Fomich');

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (3, 'Producto #3', NULL);

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (4, 'Producto #4', NULL);

Al intentar ejecutar esas sentencias de inserción de registros se genera un mensaje de error para la última:

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
Msg 2601, Level 14, State 1, Line ...
Cannot insert duplicate key row in object 'dbo.Producto' with unique index 'UX_Producto_NombreClave'. The duplicate key value is ().

The statement has been terminated.

La causa del error se debe esencialmente a que el tipo de índice creado no permite la inserción de múltiples valores no conocidos NULL.

Para resolver esta limitación, SQL Server cuenta con la función de creación de índices filtrados; esto es, la especificación de una condición para un subconjunto determinados valores del dominio de un tipo de dato (Brimhall et al, 2015).

Proceso de la solución:

Eliminación del índice creado anteriormente:

DROP INDEX Producto.UX_Producto_NombreClave;

Creación del nuevo índice único filtrado:

CREATE UNIQUE INDEX UX_Producto_NombreClave ON Producto(NombreClave) WHERE NombreClave IS NOT NULL;

Nótese la especificación del filtro a través de WHERE NombreClave IS NOT NULL.: con esto se está indiciado que el campo NombreClave solo debe conservar la unicidad sobre valores distintos a NULL.

A continuación se han de insertar otros registros

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (4, 'Producto #4', NULL);

INSERT INTO Producto (IdProducto, NombreProducto, NombreClave)
VALUES (5, 'Producto #5', NULL);

Ahora ya es permitido la inserción de múltiples valores NULL:

(1 row(s) affected)

(1 row(s) affected)

Contenido de la tabla Producto:
Contenido de la tabla Producto
Figura 1. Contenido de la tabla Producto.

7. Conclusiones

Se ha demostrado cómo a través de un índice único filtrado es posible establecer una condición sobre la unicidad para los valores de una columna o varias columnas que pertenezcan al índice. En otras palabras: este tipo de operación es de inmensa utilidad para el programador de bases de datos, pues le permitirá aplicar una condición de unicidad para un subconjunto de datos que pertenezcan a un índice único. La próxima receta T-SQL explica cómo forzar la integridad referencial sobre columnas que permiten valores NULL.

8. Literatura & Enlaces

Brimhall, J., Dye, D., Gennick, J., Roberts, A., Sheffield, W. (2012). SQL Server 2012 T-SQL Recipes - A Problem-Solucion Approach. United States: Apress.
Create Unique Indexes (2015, diciembre 4). Recuperado desde: https://msdn.microsoft.com/en-us/library/ms187019.aspx.
Create Nonclustered Indexes (2015, diciembre 4). Recuperado desde: https://msdn.microsoft.com/en-us/library/ms189280.aspx.


V

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.