Exigir la integridad de los datos con restricciones
Las restricciones y los objetos de secuencia son opciones de diseño que impiden problemas de datos antes de que se produzcan. Una restricción de clave externa que falta significa que es posible que los registros huérfanos ya existan en la base de datos. La adición de objetos de secuencia más adelante para reemplazar las columnas de identidad requiere cambios en todas las aplicaciones. El código de aplicación puede validar los datos, pero los usuarios pueden omitirlos a través de importaciones masivas, consultas directas o nuevas aplicaciones que omiten la validación.
Las restricciones de base de datos aplican reglas en el nivel de motor, por lo que siempre se aplican. Las decisiones que tome durante el diseño, como las reglas que se aplicarán en la base de datos y si usar columnas o secuencias de identidad, afectan a la calidad de los datos durante la vida útil de la aplicación.
Comprender cuándo usar restricciones
Los problemas de calidad de los datos son costosos. La mala calidad de los datos conduce a decisiones empresariales incorrectas, integraciones con errores y infracciones de cumplimiento. A diferencia de la validación de nivel de aplicación que puede ser incoherente en distintas aplicaciones que acceden a la misma base de datos, las restricciones aplican reglas en el nivel del motor de base de datos donde no se pueden omitir mediante código de aplicación, consultas ad hoc, scripts SQL directos o importaciones masivas. Todas INSERTlas operaciones , UPDATEy DELETE deben satisfacer todas las restricciones definidas antes de que el motor de base de datos confirme el cambio.
Aplicación de restricciones de base de datos
Las restricciones impiden problemas de calidad de datos antes de dañar la base de datos. En la tabla siguiente se muestra cómo cada tipo de restricción aborda problemas de integridad de datos específicos:
| Problema | Restricción | Example |
|---|---|---|
| Registros huérfanos | CLAVE EXTRANJERA | Evita pedidos sin clientes válidos |
| Datos duplicados | UNIQUE | Detiene los registros de correo electrónico duplicados |
| Datos no válidos | CHECK | Rechaza los precios negativos o las fechas de nacimiento futuras. |
| Faltan datos críticos | NOT NULL | Impide registros incompletos |
| Incoherencia referencial | CLAVE EXTRANJERA | Mantiene la integridad de los datos entre tablas. |
Considere una empresa minorista que no definió una restricción única en su columna de correo electrónico de cliente. Con el tiempo, los mismos clientes se registraron varias veces con direcciones de correo electrónico idénticas. Cuando el marketing envió campañas promocionales, algunos clientes recibieron tres copias del mismo correo electrónico, aumentando los costos y dañando la confianza del cliente. Agregar UNIQUE (EmailAddress) a la definición de tabla habría evitado que se inserten estos duplicados.
Las restricciones aplican reglas en el nivel del motor de base de datos, lo que garantiza la calidad de los datos independientemente de cómo entran los datos en el sistema. La validación de la aplicación se puede omitir, varía según la aplicación y es más difícil de mantener. Las restricciones de base de datos siempre están aplicadas, están centralizadas y proporcionan una fuente única de verdad.
Las restricciones garantizan la calidad y la coherencia de los datos en el nivel de base de datos.
Utilice restricciones de clave principal
Las restricciones de clave principal garantizan datos únicos y aplican la integridad de la entidad. Al especificar una restricción de clave principal, el motor de base de datos crea automáticamente un índice único para las columnas de clave principal. Una tabla solo puede contener una restricción de clave principal y todas las columnas definidas dentro de una restricción de clave principal deben definirse como NOT NULL.
Puede crear una clave principal mediante la PRIMARY KEY restricción . Este es un ejemplo:
CREATE TABLE Customer (
CustomerID INT PRIMARY KEY IDENTITY(1,1),
EmailAddress NVARCHAR(100) NOT NULL
);
Uso de restricciones de clave externa
Las restricciones de clave externa aplican la integridad referencial mediante el control de los datos que se pueden almacenar en la tabla de claves externas. Una restricción de clave externa impide cambios en los datos de la tabla de claves principal si esos cambios invalidan el vínculo a los datos de la tabla de claves externas.
Puede definir acciones referenciales en cascada como CASCADE, SET NULLo SET DEFAULT para especificar lo que sucede cuando un usuario intenta eliminar o actualizar una clave a la que apuntan claves externas existentes. Aunque no es necesario crear manualmente un índice en columnas de clave externa , suele ser útil porque las columnas de clave externa se usan con frecuencia en criterios de combinación.
Puede crear una clave externa mediante la FOREIGN KEY restricción con una REFERENCES cláusula . Este es un ejemplo:
CREATE TABLE Order (
OrderID INT PRIMARY KEY IDENTITY,
CustomerID INT NOT NULL,
OrderDate DATETIME2,
FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID)
);
Uso de restricciones únicas
Las restricciones únicas garantizan que no se escriban valores duplicados en columnas específicas que no participen en una clave principal. A diferencia de las restricciones PRIMARY KEY las restricciones UNIQUE permiten valores NULL. Sin embargo, de la misma forma que cualquier valor incluido en una restricción UNIQUE, solo se admite un valor NULL por columna. El motor de base de datos crea automáticamente un índice no clúster único para aplicar el requisito de unicidad.
Puede crear una restricción única mediante la UNIQUE palabra clave . Este es un ejemplo:
CREATE TABLE Product (
ProductID INT PRIMARY KEY,
SKU NVARCHAR(50) UNIQUE,
ProductName NVARCHAR(100)
);
Uso de restricciones de comprobación
Las restricciones check aplican la integridad del dominio limitando los valores aceptados por una o varias columnas. Puede crear una CHECK restricción con cualquier expresión lógica que, basada en operadores lógicos, devuelva TRUE o FALSE. Puede aplicar varias CHECK restricciones a una sola columna o aplicar una restricción única CHECK a varias columnas.
Dado que los valores NULL se evalúan como UNKNOWN, su presencia en expresiones podría invalidar una restricción. Por ejemplo, una restricción MyColumn = 10 en una columna INT todavía permite insertar NULL porque NULL no se evalúa a FALSE.
Puede crear una restricción CHECK mediante la CHECK palabra clave con una expresión lógica. Este es un ejemplo:
CREATE TABLE Employee (
EmployeeID INT PRIMARY KEY,
HireDate DATE,
Salary DECIMAL(10,2),
CHECK (Salary >= 20000),
CHECK (HireDate <= GETDATE())
);
Uso de restricciones predeterminadas
Las restricciones predeterminadas proporcionan valores predeterminados cuando no se especifica ningún valor durante INSERT las operaciones. Al trabajar con proyectos de base de datos, se recomienda crear restricciones con nombres explícitos en lugar de permitir nombres generados por el sistema, que difieren entre entornos.
Puede crear una restricción DEFAULT mediante la DEFAULT palabra clave . Este es un ejemplo:
CREATE TABLE Activity (
ActivityID INT PRIMARY KEY IDENTITY,
Description NVARCHAR(200),
CreatedDate DATETIME2 CONSTRAINT DF_Activity_CreatedDate DEFAULT GETUTCDATE(),
IsActive BIT CONSTRAINT DF_Activity_IsActive DEFAULT 1
);
Uso de objetos de secuencia
Un objeto de secuencia es un objeto enlazado a esquema definido por el usuario que genera una secuencia de valores numéricos según la especificación con la que se creó la secuencia. A diferencia de las columnas de identidad, las secuencias no están asociadas a tablas específicas. Las aplicaciones hacen referencia a un objeto de secuencia para recuperar su siguiente valor y la relación entre secuencias y tablas se controla mediante la aplicación.
Las columnas de identidad funcionan bien cuando se necesita numeración automática para una sola tabla. Sin embargo, se limitan a esa única tabla. No puede compartir los números entre varias tablas, obtener el siguiente valor antes de insertar una fila o restablecer fácilmente el contador. Los objetos de secuencia resuelven estos problemas mediante la generación de números independientemente de cualquier tabla.
Comprender cuándo usar secuencias
Utilice secuencias en lugar de columnas de identidad en los siguientes escenarios:
- Serie de números compartidos : la aplicación requiere compartir una sola serie de números entre varias tablas o varias columnas dentro de una tabla.
- Serie de números de ciclo : la aplicación debe reiniciar la serie de números cuando se alcanza un número especificado. Por ejemplo, después de asignar valores entre 1 y 10, la aplicación comienza de nuevo a asignar valores entre 1 y 10.
-
Valores de secuencia ordenados : la aplicación requiere que otro campo ordene los valores de secuencia. La
NEXT VALUE FORfunción puede aplicar laOVERcláusula , que garantiza que los valores devueltos se generan en el orden de laORDER BYcláusula . -
Reservar varios números : una aplicación debe reservar varios números secuenciales a la vez. Solicitar valores de identificador podría dar lugar a brechas si otros procesos asignaran simultáneamente números. La llamada a
sp_sequence_get_rangerecupera varios números de la secuencia a la vez. - Especificación modificable : debe cambiar la especificación de la secuencia, como el valor de incremento, después de la creación.
Los objetos de secuencia pueden ofrecer más flexibilidad que las columnas de identidad:
| Característica | Sequence | identidad |
|---|---|---|
| Vinculado a la tabla | No | Sí |
| Compartido entre tablas o columnas | Sí | No |
| Obtener el siguiente valor antes de la operación de inserción | Sí | No |
| Valores mínimos y máximos personalizados | Sí | Limitado |
| Recuperar varios números a la vez | Sí | No |
| Ciclo/reinicio al número especificado de veces | Sí | No |
| Ordenar valores por otro campo | Sí | No |
| Cambiar el incremento después de la creación | Sí | No |
Use una columna de identidad cuando necesite una clave principal de creación automática simple para una sola tabla y no sea necesario compartir la misma serie de números entre varias tablas o recuperar el siguiente valor antes de insertar la fila.
Use una secuencia cuando la aplicación requiera un número antes de realizar la inserción, debe compartir una sola serie entre varias tablas, debe reiniciar la serie de números cuando se alcanza un número especificado o debe reservar varios números secuenciales a la vez.
Entender las limitaciones de la secuencia
A diferencia de las columnas de identidad, los valores de secuencia no se protegen automáticamente después de la inserción en una tabla. Además, la unicidad no se aplica automáticamente a los valores de secuencia. Si los valores de secuencia de una tabla deben ser únicos, cree una restricción única en la columna.
Los números de secuencia se generan fuera del ámbito de la transacción actual. Se utilizan tanto si la transacción que usa el número de secuencia se confirma como si se revierte.
Puede crear un objeto de secuencia mediante la CREATE SEQUENCE instrucción con parámetros opcionales para el inicio, el incremento y el intervalo. Este es un ejemplo:
-- Create sequence
CREATE SEQUENCE OrderNumber
START WITH 1000
INCREMENT BY 1
MINVALUE 1000
MAXVALUE 999999
NO CYCLE;
-- Use sequence in INSERT with NEXT VALUE FOR function
INSERT INTO Order (OrderID, CustomerID, OrderNumber, OrderDate)
VALUES (1, 100, NEXT VALUE FOR OrderNumber, GETDATE());
-- Get next value before INSERT
DECLARE @NextOrderNum INT = NEXT VALUE FOR OrderNumber;
SELECT @NextOrderNum;
-- Get multiple sequence numbers at once for batch processing
DECLARE @FirstSeq INT, @LastSeq INT;
EXEC sp_sequence_get_range
@sequence_name = N'OrderNumber',
@range_size = 100,
@range_first_value = @FirstSeq OUTPUT,
@range_last_value = @LastSeq OUTPUT;
-- Reset sequence
ALTER SEQUENCE OrderNumber RESTART WITH 1000;
En este ejemplo se crea una secuencia denominada OrderNumber que comienza en 1000, se incrementa en 1 y se detiene en 999999 sin retroceder. La NEXT VALUE FOR función recupera el siguiente número disponible, ya sea insertado durante una INSERT instrucción o asignado a una variable antes de la inserción cuando la aplicación necesita hacer referencia al valor primero. Para las operaciones por lotes que requieren varios números secuenciales a la vez, sp_sequence_get_range reserva un bloque de 100 números, devolviendo los valores primero y último del intervalo. La ALTER SEQUENCE instrucción restablece la secuencia a 1000 cuando sea necesario.
Las restricciones son decisiones arquitectónicas que impiden problemas antes de que se produzcan. Una restricción que falta CHECK permite que los datos no válidos dañen la base de datos de forma silenciosa. Al elegir columnas de identidad cuando se necesita numeración cruzada entre tablas, se obliga a implementar soluciones alternativas a nivel de aplicación. Las restricciones definidas en el nivel de base de datos protegen la calidad de los datos independientemente de qué aplicación, herramienta o script accedan a la base de datos. Estas decisiones dan forma a la integridad de tus datos durante la vida útil de tu aplicación.