另一列的上下文中的SQL Server唯一自动增量列

Ant*_*kov 13 sql-server sql-server-2005 auto-increment

假设该表有两列:

ParentEntityId int foreign key
Number int
Run Code Online (Sandbox Code Playgroud)

ParentEntityId 是另一个表的外键.

Number是一种本地身份,即它在单身内是独一无二的ParentEntityId.

通过这两列上的唯一键可轻松实现唯一性.

如何在插入Number的上下文中自动递增ParentEntityId


附录1

为了澄清这个问题,这里有一个摘要.

ParentEntity有多个ChildEntity,每个都ChiildEntity应该Number在其上下文中具有唯一的增量ParentEntity.


附录2

对待ParentEntity一个客户.

治疗ChildEntity作为一种秩序.

因此,每个客户的订单应编号为1,2,3等.

Aar*_*ght 9

好吧,这种类型的列没有本机支持,但您可以使用触发器实现它:

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
Run Code Online (Sandbox Code Playgroud)

没有测试,但我很确定它会工作.如果你有一个主键,你也可以将它作为AFTER触发器实现(我不喜欢使用INSTEAD OF触发器,当你需要在6个月后修改它们时,它们更难理解).

只是为了解释这里发生了什么:

  • SERIALIZABLE是最严格的隔离模式; 它保证一次只有一个数据库事务可以执行这些语句,这是我们需要的,以保证这个"序列"的完整性.请注意,这会不可逆转地促进整个事务,因此您不希望在长时间运行的事务中使用它.

  • CTE获取已用于每个父ID的最高数字;

  • ROW_NUMBERPARTITION BY从数字1开始为每个父ID()生成一个唯一的序列; 如果有一个获得新序列,我们将其添加到先前的最大值.

我可能还应该提一下,如果你一次只需要插入一个新的子实体,你最好只是通过存储过程汇集这些操作而不是使用触发器 - 你肯定会从中获得更好的性能.这就是hierarchyidSQL '08中当前使用列的方式.