Tsql T-SQL中的序列生成器
我们有一个Oracle应用程序,它使用标准模式填充代理键。我们有一系列外部行(具有代理键的特定值)和其他具有内部值的行。 我们使用以下Oracle触发器片段来确定在插入时如何处理代理键:Tsql T-SQL中的序列生成器,tsql,sequence,Tsql,Sequence,我们有一个Oracle应用程序,它使用标准模式填充代理键。我们有一系列外部行(具有代理键的特定值)和其他具有内部值的行。 我们使用以下Oracle触发器片段来确定在插入时如何处理代理键: IF :NEW.SurrogateKey IS NULL THEN SELECT SurrogateKey_SEQ.NEXTVAL INTO :NEW.SurrogateKey FROM DUAL; END IF; 如果提供的代理项为null,则从指定序列中获取一个值,否则将提供的代理项传递到行 我似乎
IF :NEW.SurrogateKey IS NULL THEN
SELECT SurrogateKey_SEQ.NEXTVAL INTO :NEW.SurrogateKey FROM DUAL;
END IF;
如果提供的代理项为null,则从指定序列中获取一个值,否则将提供的代理项传递到行
我似乎找不到一个简单的方法来实现这一点,这就是t-SQL。有各种各样的方法,但没有一种像Oracle和其他符合SQL-92的DBs那样使用序列生成器的概念
有人知道在SQLServerT-SQL中实现这一点的真正有效方法吗?顺便说一下,如果有帮助的话,我们使用的是SQL Server 2008。您可能需要查看IDENTITY。这将为您提供一列,插入行时将确定该列的值 这可能意味着您必须插入行,然后使用SCOPE_IDENTITY()确定值
这里还有一篇关于在SQL Server中模拟Oracle序列的文章:标识是一种方法,尽管它将在每个表级别生成唯一标识符 另一种方法是使用唯一标识符,特别是使用NewSequantialID()生成的id总是大于最后一个id。这种方法的问题是不再处理整数
模拟oracle方法的最接近的方法是使用一个带有计数器字段的单独表,然后编写一个用户定义的函数来查询此字段,对其进行递增并返回值。下面是一种使用表存储上一个序列号的方法。存储过程非常简单,其中的大部分内容都是因为我很懒,不喜欢在我忘记某件事情时出现意外情况,所以…这里是: -----创建序列值表
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[SequenceTbl]
(
[CurrentValue] [bigint]
) ON [PRIMARY]
GO
-----------------创建存储过程
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[sp_NextInSequence](@SkipCount BigInt = 1)
AS
BEGIN
BEGIN TRANSACTION
DECLARE @NextInSequence BigInt;
IF NOT EXISTS
(
SELECT
CurrentValue
FROM
SequenceTbl
)
INSERT INTO SequenceTbl (CurrentValue) VALUES (0);
SELECT TOP 1
@NextInSequence = ISNULL(CurrentValue, 0) + 1
FROM
SequenceTbl WITH (HoldLock);
UPDATE SequenceTbl WITH (UPDLOCK)
SET CurrentValue = @NextInSequence + (@SkipCount - 1);
COMMIT TRANSACTION
RETURN @NextInSequence
END;
GO
--------使用Sql Manager中的存储过程检索测试值
declare @NextInSequence BigInt
exec @NextInSequence = sp_NextInSequence;
--exec @NextInSequence = sp_NextInSequence <skipcount>;
select NextInSequence = @NextInSequence;
精明的人会注意到存储的进程有一个参数(可选)。这是为了允许调用者在调用者有多条记录需要唯一ID的情况下保留一个ID块-使用SkipCount,调用者只需对需要的ID进行一次调用。
如果在创建表时记得插入记录,则可以删除整个“IF EXISTS…INSERT INTO…”块。如果您还记得用一个值(您的种子值-一个永远不会用作ID的数字)插入该记录,那么您还可以删除select的ISNULL(…)部分,并仅使用CurrentValue+1。
现在,在任何人发表评论之前,请注意我是一名软件工程师,而不是dba!因此,任何关于使用“Top 1”、“With(HoldLock)”和“With(UPDLock)”的建设性批评都是受欢迎的。我不知道这会扩展到什么程度,但到目前为止,这对我来说还可以…谢谢Matthieu,我知道表的IDENTITY属性,但我正试图避免它,因为我希望保留我们目前拥有的灵活性。另外,您所指的文章使用了额外的表和查找,这是我试图避免的。您还需要为每个“序列”创建一个表;但是有一个特殊的要求,代理键必须是整数。据我所知,unque标识符是guid或uuid。请参阅建设性的批评:)不要玩那些锁,你会受伤的。。。为了避免死锁,我建议使用标识为(1,1)的表,第一个操作将是insert(insert SEQUENCE TBL默认值),您将获得scope_identity(),第二个操作是删除等于该数字的行。这可以通过行级锁定进行序列化。
select * from SequenceTbl;