Chà, không có hỗ trợ gốc nào cho loại cột này, nhưng bạn có thể triển khai nó bằng cách sử dụng trình kích hoạt:
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
Chưa được thử nghiệm nhưng tôi khá chắc chắn rằng nó sẽ hoạt động. Nếu bạn có khóa chính, bạn cũng có thể triển khai khóa này dưới dạng AFTER
trigger (Tôi không thích sử dụng INSTEAD OF
kích hoạt, chúng khó hiểu hơn khi bạn cần sửa đổi chúng 6 tháng sau).
Chỉ để giải thích những gì đang xảy ra ở đây:
-
SERIALIZABLE
là chế độ cách ly nghiêm ngặt nhất; nó đảm bảo rằng chỉ một giao dịch cơ sở dữ liệu tại một thời điểm có thể thực hiện các câu lệnh này, mà chúng tôi cần để đảm bảo tính toàn vẹn của "chuỗi" này. Lưu ý rằng điều này không thể thay đổi thúc đẩy toàn bộ giao dịch, vì vậy bạn sẽ không muốn sử dụng điều này trong một giao dịch dài hạn. -
CTE chọn số cao nhất đã được sử dụng cho mỗi ID mẹ;
-
ROW_NUMBER
tạo một chuỗi duy nhất cho mỗi ID mẹ (PARTITION BY
) bắt đầu từ số 1; chúng tôi thêm giá trị này vào giá trị tối đa trước đó nếu có một giá trị để có được chuỗi mới.
Tôi có lẽ cũng nên đề cập rằng nếu bạn chỉ cần chèn một thực thể con mới tại một thời điểm, thì tốt hơn hết bạn chỉ nên tạo các thao tác đó thông qua một quy trình được lưu trữ thay vì sử dụng trình kích hoạt - bạn chắc chắn sẽ nhận được hiệu suất tốt hơn từ nó . Đây là cách nó hiện được thực hiện với hierarchyid
các cột trong SQL '08.