如何在一个表中使用多个身份号码?

时间:2010-05-04 13:54:28

标签: sql sql-server database-design

我有一个创建可打印表单的Web应用程序,这些表单上有唯一的编号,问题是我有2个表单需要为它们创建单独的数字。 即)

Form1-编号2000000-2999999
Form2-编号3000000-3999999

dbo.test2 - 是我的表单信息表
Tsel - 是我3000000系列号的autoinc表 Tadv - 是我2000000系列号码的autoinc表

我所做的是创建2个只有autoinc行的表(一个用于2000000个系列号,一个用于3000000个系列号),然后我创建了一个触发器,将记录添加到相应的表中,读回autoinc号并添加它存储在我的表中,用于存储表单信息,包括刚刚为正确的表单系列创建的autoinc编号。

虽然它确实有效,但我担心这些数字会在负载下混乱。 当很多人使用系统时,我不确定@@ IDENTITY是否会始终返回正确的值。 (我不能重复,我需要使用上面的编号表格。

见下面的代码。 **** TRIGGER ****

CREATE TRIGGER MAKEANID2 ON dbo.test2
AFTER INSERT
AS
SET NOCOUNT ON
declare @someid int
declare @someid2 int
declare @startfrom int
declare @test1 varchar(10)

select @someid=@@IDENTITY

select @test1 = (Select name1 from test2 where sysid = @someid )
if @test1 = 'select'
begin
 insert into Tsel Default values
 select @someid2 = @@IDENTITY
end

if @test1 = 'adv'
begin
 insert into Tadv Default values
 select @someid2 = @@IDENTITY
end

update test2
set name2=(@someid2) where sysid = @someid
SET NOCOUNT OFF

2 个答案:

答案 0 :(得分:1)

保持两个ID同步的最佳方法是根据实际标识列创建持久Computed Column。其中Col1是标识列,Col2是持久计算列,它是基于Col1的某些公式的结果。然后你甚至可以Create Indexes on Computed Columns

测试一下:

CREATE TABLE YourTable
(Col1 int not null identity(2000000,1)
,Col2 AS (Col1-2000000+3000000) PERSISTED
,Col3  varchar(5)
)
GO

insert into YourTable (col3) values ('a')
insert into YourTable (col3) SELECT 'b' UNION SELECT 'c'

SELECT * FROM YourTable

输出:

Col1        Col2        Col3
----------- ----------- -----
2000000     3000000     a
2000001     3000001     b
2000002     3000002     c

(3 row(s) affected)

编辑在OP评论之后,我仍然不能100%确定你的目标。

我从未使用过SQL Server 2000(我们跳过了那个版本),我真的不想查看如何在该版本中执行所有操作,如果没有OUTPUT子句和ROW_NUMBER(),CTE等,它是如此有限

我可以想到三种方法:

1)你可以创建一个序列表,你有两行一个用于A,一个用于B,每次你需要插入一个,查找,增加和保存你需要的seq类型的值然后插入该值。例如,如果要插入类型“A”行,请执行以下操作:

INSERT INTO test2
        (col1, col2, col3,...)
    SELECT
        ISNULL(MAX(NextSeq),0)+1, col2, col3,...
        FROM YourSequenceTable WITH (UPDLOCK, HOLDLOCK)
        WHERE SequenceType='A'

UPDATE YourSequenceTable 
    SET NextSeq=ISNULL(NextSeq,0)+1
    WHERE SequenceType='A'

2)更改您的表结构,只需将数据保存在Tsel或Tadv中,并将触发器插入到第三个公用表表中,您可以在其中获得额外的“公共”标识。普通表就像

CommonTable
ID      int not null indentity(1,1) primary key
TselID  int null FK to Tsel.PK 
TadvID  int null FK to Tadv.PK

3)如果你需要一个表,试试这个,这是一个真正的黑客。更改您的Tsel和Tadv表以包含所有必需的列,并在值为INSERT INTO Tsel时从应用程序select更改并触发获取该标识值,然后将其插入test2,然后从中删除数据TSEL。然后,从值为adv INSERT INTO Tadv的应用程序中,只有CREATE Trigger MAKEANID2_Tsel ON dbo.Tsel AFTER INSERT AS --copy data from Tsel into test2., test2 can still have its own identity value INSERT INTO test2 (PK, col1, col2, col3,...) SELECT col0, col1, col2, col3,.... FROM INSERTED --remove rows from Tsel, which were just copied and not needed anymore. DELETE Tsel WHERE PK IN (SELECT PK FROM INSERTED) GO 的触发器将该数据插入test2,并从Tadv中删除数据。您需要在Tsel和Tadv中包含所有数据列,以便触发器可以将值复制到test2,但触发器将从那里删除行(即使删除了原始行,标识也将是顺序的。)

您的Tsel触发器如下所示:

{{1}}

答案 1 :(得分:0)

你担心@@ identity是正确的,它不是一个推荐的代码,如果somone在其他地方添加了一个不同的触发器,它会使一个身份不相关而且首先会触发,这就是你将获得的价值。

但是你有更大的问题。您的触发器被定义为一次只能处理一个记录。这对触发器来说非常非常糟糕。触发器对数据集进行操作,并且即使您认为一次插入的记录永远不会超过一个,也必须始终设置为处理数据集而不是一个记录。此外,您不需要询问身份,您可以将所有记录中的所有记录的标识插入到名为inserted的触发器中的可伪造的availlble中。

现在阅读你的一条评论,你说你根本没有任何遗漏的价值。在任何情况下,您不能使用标识列,因为如果任何事务被回滚,它将有间隙。您必须编写自己的流程以根据最后一个数字创建数字,并注意竞争条件。