Bueno, no hay soporte nativo para este tipo de columna, pero podría implementarlo usando un disparador:
CREATE TRIGGER tr_MyTable_Number
ON MyTable
INSTEAD OF INSERT
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN;
WITH MaxNumbers_CTE AS
(
SELECT ParentEntityID, MAX(Number) AS Number
FROM MyTable
WHERE ParentEntityID IN (SELECT ParentEntityID FROM inserted)
)
INSERT MyTable (ParentEntityID, Number)
SELECT
i.ParentEntityID,
ROW_NUMBER() OVER
(
PARTITION BY i.ParentEntityID
ORDER BY (SELECT 1)
) + ISNULL(m.Number, 0) AS Number
FROM inserted i
LEFT JOIN MaxNumbers_CTE m
ON m.ParentEntityID = i.ParentEntityID
COMMIT
No probado, pero estoy bastante seguro de que funcionará. Si tiene una clave principal, también podría implementarla como AFTER
activador (no me gusta usar INSTEAD OF
factores desencadenantes, son más difíciles de entender cuando necesita modificarlos 6 meses después).
Solo para explicar lo que está pasando aquí:
-
SERIALIZABLE
es el modo de aislamiento más estricto; garantiza que solo una transacción de base de datos a la vez puede ejecutar estas declaraciones, que necesitamos para garantizar la integridad de esta "secuencia". Tenga en cuenta que esto promueve irreversiblemente toda la transacción, por lo que no querrá usar esto dentro de una transacción de larga duración. -
El CTE recoge el número más alto ya utilizado para cada ID de padre;
-
ROW_NUMBER
genera una secuencia única para cada ID principal (PARTITION BY
) a partir del número 1; agregamos esto al máximo anterior si hay uno para obtener la nueva secuencia.
Probablemente también debería mencionar que si solo necesita insertar una nueva entidad secundaria a la vez, es mejor canalizar esas operaciones a través de un procedimiento almacenado en lugar de usar un activador; definitivamente obtendrá un mejor rendimiento. . Así es como se hace actualmente con hierarchyid
columnas en SQL '08.