我们有一个多租户数据库,它拥有多个客户,每个客户都拥有一组用户(简化示例,省略了从用户到客户的外键规范):
CREATE TABLE dbo.Customers
(
CustomerId INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(256) NOT NULL
)
CREATE TABLE dbo.Users
(
User INT NOT NULL IDENTITY(1, 1),
CustomerId INT NOT NULL,
)
作为此设计的一部分,用户需要拥有会员编号,在我们设计时,我们决定使用UserId作为会员编号,但是随着所有事情的增加,这个要求已经增长,这不再是两个选项原因:
在我们在每台服务器上升级到2012后,重新启动列会跳过1000个值,我们使用了此处显示的解决方法:http://www.codeproject.com/Tips/668042/SQL-Server-2012-Auto-Identity-Column-Value-Jump-Is(-t272)来阻止这种情况发生,但让我们意识到IDENTITY(1,1)不够好。
我们现在真正想要的是确保每个客户的数量增加,但必须是永久性的,一旦分配就不能改变。
显然,序列不会再次起作用,它需要按照客户的要求,我们还需要对每个客户/用户强制执行一个唯一约束,并确保一旦分配就永远不会更改该值,如果删除用户则不会更改(虽然这不应该发生,因为我们不会删除用户但是将其标记为已存档,但我想保证这不会影响它)。
以下是我编写的可以生成数字的示例,但是使用此类或类似内容的最佳方式是确保每个客户/用户的唯一顺序值,而不会出现任何问题,因为用户可能是从不同的会议同时创建。
ROW_NUMBER() OVER (ORDER BY i.UserId) + ISNULL((SELECT MAX(users.MembershipNumber)
FROM [User].Users users
WHERE users.Customers_CustomerId = i.Customers_CustomerId), 0)
编辑:澄清
我道歉我只是重新阅读了我的问题并且我没有说清楚,我们不打算替换UserId,我们很满意所有外键上使用的差距和每个数据库标识符的唯一性,我们是什么正在寻找添加的是一个会向用户显示的MembershipNumber,这就是为什么它需要按顺序每个客户而没有间隙,因为这个会员号将用于提供给用户的卡,因此需要是唯一的。
答案 0 :(得分:0)
由于您已经发现了Identity列的问题以及如何修复它,我不会说它不够好。
但是,它似乎不适合您的需求,因为您希望用户号码按每个客户递增。
我建议将User列保留为Identity列和表的主键,并添加另一列以按客户指定用户号。此列也是一个整数,其UDF
结果的默认值将计算每个客户的下一个数字(see example in this post)。
您可以通过在users表上使用而不是更新触发器来保护该值不会发生变化。
这种方法可以保留单个列主键,您可以为每个客户提供唯一的顺序用户号。
<强>更新强>
显然,it is impossible to send column values to a default constraint.
但您仍然可以使用instead of insert
触发器来实现目标。
答案 1 :(得分:0)
这是因为序列对象的默认缓存sqlserver实现。看到这个前一个主题 Identity increment is jumping in SQL Server database
如果差距是个问题,sql-server2012引入了Sequence对象。您可以使用NOCACHE声明这些内容,因此重新启动服务器不会产生间隙。
答案 2 :(得分:0)
我想分享一下我的想法。请参阅下文。
创建单独的表格,其中包含CustomerID和Count列,如下所示。
CREATE TABLE dbo.CustomerSequence
(
@CustomerID int,
@Count int
);
写下某种存储过程,如下所示。
CREATE PROC dbo.usp_GetNextValueByCustomerID
@CustomerID int,
@Count int OUTPUT
AS
BEGIN
UPDATE dbo.CustomerSequence
SET @Count = Count += Count
WHERE CustomerID = @CustomerID;
END
只需通过传递CustomerID并从中获取下一个序列值来调用上述存储过程。