【问题标题】:Custom Identifier generation in SQL Server Stored ProcedureSQL Server 存储过程中的自定义标识符生成
【发布时间】:2012-12-29 08:22:19
【问题描述】:

目前正在处理多租户应用程序,在存储过程中生成标识符时遇到问题。

我有一张这张表,里面有关于租户的元信息。

租户

TenantId
Name
IDPrefix,   -->Like SFT
IDStart     --> 000001

客户

TenantID
ClientIdentfier --> Like SFT000001

在存储过程中,我想生成下一个ClientIdentifier,例如SFT000002

如何根据最后一个ClientIdentifier value + 1 做到这一点?

我知道下面的代码只取最后一个值。

select max(ClientID) + 1 from Client will give 1,2,etc

但我觉得我做不到

 DECLARE @CIdentier Varchar(50);

 select @CIdentier = select max(ClientIdentifier) + 1 from Client 
                                            to produce 'SFT000002

如何在存储过程中这样做?

编辑:

尝试了 mark_s 的答案,效果很好!!!

【问题讨论】:

  • 之前在 SO.... 上被问过。
  • @MitchWheat 我可以得到那个 SO 链接吗?我搜索并失败了。
  • SELECT MAX(ClientID) + 1 方法在负载下永远不安全 - 你会得到重复。
  • 使用IDENTITY(1,1),如果需要生成像SFTxxxxxx这样的ID,可以从ID生成,并且可以避免重复
  • @marc_s 谢谢你的提示。但是有没有一种很好的方法可以在负载下做到这一点?该应用程序将被许多租户使用,因此,如果您添加更多点做,将会有所帮助

标签: sql sql-server sql-server-2008 stored-procedures


【解决方案1】:

这种方法在负载下是安全的,例如它不会返回任何重复项,即使同时有很多客户端请求(这是从@remusrusanu 对 SO 上的另一个问题的回答“借用”的)。

基本上,您需要一个包含TenantIDTenantPrefixCurrentValue 列的序列表,然后您可以使用这样的存储过程来安全地获取新值:

-- add a IDValue column to your Tenant table
ALTER TABLE dbo.Tenant
ADD IDValue INT NOT NULL DEFAULT(0)

-- create this procedure to fetch the next value for any given tenant
CREATE PROCEDURE dbo.GetNextTenantID
   @tenantID INT,    
   @NextID VARCHAR(15) OUTPUT
AS
   SET NOCOUNT ON;

   DECLARE @Out TABLE (NextVal INT, Prefix CHAR(3))

   UPDATE dbo.Tenant
   SET IDValue = IDValue + 1
   OUTPUT INSERTED.IDValue, INSERTED.IDPrefix INTO @Out(NextVal, prefix)

   SELECT TOP 1 @nextID = Prefix + CAST(NextVal AS VARCHAR(10)) FROM @Out
GO

这里的要点是:你必须增加 IDValue 并在 single UPDATE 语句中返回它。只有使用这种方法,您才能在负载下保持安全 - 所有首先具有 SELECT、增量,然后是 UPDATE 的方法都安全,并且可以返回重复项。

更新:不能仅仅将这段 sn-p 代码包含到你的一个更大的过程中!保留此过程原样,然后从您的存储过程中调用它 - 类似于:

ALTER PROCEDURE [dbo].[AddClient]  
(
   @TenantId INT,
   @FirstName NVARCHAR(100),
   @LastName NVARCHAR(100),
   @ContactPerson NVARCHAR(100)
)
AS 
BEGIN 
     SET NOCOUNT ON   

     IF @TenantId IS NULL 
        RAISERROR('The value for @TenantID should not be null', 15, 1) -- with log

     DECLARE @new_person_id INT
     DECLARE @new_patient_id INT
     DECLARE @ClientIdentifier NVARCHAR(50)

     -- call the stored procedure to get the next ClientIdentifier here
     EXEC dbo.GetNextTenantID @TenantID, @ClientIdentifier OUTPUT

     -- then go on and do your other lines of code from here on out .....
     ......
END

【讨论】:

  • 非常感谢。我就这样走!
  • 我可以把这个 GetNextTenantID 作为函数并在存储过程中使用它吗?
  • @user1909604:不,你不能——函数不能修改数据库
  • @user1909604:如果您尝试将其转换为函数,您将收到如下错误:Msg 443, Level 16, State 15, Procedure ......, Line 7 / Invalid use of a side-effecting operator 'UPDATE' within a function.
  • 我在程序内部尝试了相同的方法,但出现了一些新错误!。用我的问题更新了这一点。请帮我解决它。
【解决方案2】:

如果你有固定的前缀长度和正确的数字长度:

Here is SQLFiddle demo

with T as 
(select 
    (isnull(max(ClientIdentfier),'SFT000000')) maxNum
from client
)

select substring(maxNum,1,3)+
       RIGHT('000000'+
             cast(cast(right(maxNum,6) as bigint)+1 as varchar(100)),
             6)
   from T

如果您需要获取已定义 TenantID 的下一个编号,例如 TenantID=2,请使用以下查询:

with T as 
(select 
    (isnull(max(ClientIdentfier),
            select top 1 IDPrefix+IDStart 
                from Tenant 
             where TenantID=2)) maxNum
from client 
     where TenantID=2
)

select substring(maxNum,1,3)+
       RIGHT('000000'+
             cast(cast(right(maxNum,6) as bigint)+1 as varchar(100)),
             6)
   from T

【讨论】:

  • 看起来不错。然而,每个租户可能有自己的标识符和起始编号。示例租户 2 可能具有“TET”和“开始编号”“20569”。有没有办法读取这些并生成下一个数字?
  • 我添加了一个查询以获取已定义租户的下一个号码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
相关资源
最近更新 更多