Sql 如何在一个表中使用多个标识号?

Sql 如何在一个表中使用多个标识号?,sql,sql-server,database-design,Sql,Sql Server,Database Design,我有一个创建可打印表单的web应用程序,这些表单上有一个唯一的编号,问题是我有两个表单,需要为它们创建单独的编号。 (工业工程) 表格1-编号2000000-299999 表格2-编号为3000000-3999999 dbo.test2-是我的表单信息表 Tsel-是我的300万系列编号的autoinc表 Tadv-是我的autoinc表格,用于2000000系列编号 我所做的是创建两个表,其中只有autoinc行(一个用于2000000系列号,一个用于3000000系列号),然后我创建了一个触

我有一个创建可打印表单的web应用程序,这些表单上有一个唯一的编号,问题是我有两个表单,需要为它们创建单独的编号。 (工业工程)

表格1-编号2000000-299999
表格2-编号为3000000-3999999

dbo.test2-是我的表单信息表
Tsel-是我的300万系列编号的autoinc表
Tadv-是我的autoinc表格,用于2000000系列编号

我所做的是创建两个表,其中只有autoinc行(一个用于2000000系列号,一个用于3000000系列号),然后我创建了一个触发器,将一条记录添加到相应的表中,读回autoinc编号并将其添加到我的表格中,该表格存储表格信息,包括刚创建的右系列表格的autoinc编号

虽然它确实有效,但我担心数据在负载下会变得混乱。 我不确定@标识在许多人使用系统时是否总是返回正确的值。(我不能有副本,我需要使用上面显示的编号表格

请参阅下面的代码。 ****触发****

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

保持两个ID同步的最佳方法是基于实际的标识列创建一个持久化列。其中Col1是标识列,Col2是持久化计算列,它是基于Col1的某个公式的结果。您甚至可以

测试这一点:

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)
编辑在OPs评论之后,我仍然无法100%确定您想要什么

我从未使用过SQL Server 2000(我们跳过了该版本),我也不想查看如何在该版本中执行所有操作,因为没有OUTPUT子句和ROW_NUMBER()、CTEs等,它是如此有限

我可以想出三种方法:

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表更改为包含所有必要的列,并在值为
时从应用程序
插入Tsel
中选择
,并使用触发器获取该标识值,然后将其插入test2,然后从Tsel中删除数据。然后,当值为
adv
just
INSERT INTO Tadv
时,从应用程序中,在该表上有一个触发器,将数据插入test2,并从Tadv中删除数据。您需要在Tsel和Tadv中包含所有数据列,以便触发器可以将值复制到test2,但触发器将从中删除行(即使删除了原始行,标识也将是顺序的)

您的Tsel触发器如下所示:

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

您担心@@identity是对的,这不是一个推荐的代码,如果其他人添加了一个插入标识的不同触发器,而该触发器是首先触发的,那么您将得到这个值

但你有更大的问题。您的触发器被设计为一次只能在一条记录上工作。这是一个非常糟糕的事情做一个触发器。触发器对数据集进行操作,即使您认为每次插入的记录不会超过一条,也必须始终设置触发器以处理数据集而不是一条记录。而且,你不知道;不需要请求标识,您已经在名为inserted的触发器中提供了psuedotable中批量插入的所有记录的标识


现在阅读您的一条评论,您说您不能有任何缺失的值。在这种情况下,您不能在任何情况下使用标识列,因为如果回滚任何事务,它将有间隙。您必须编写自己的流程,根据最后一个号码创建号码,并注意比赛条件。

很遗憾您没有使用Oracle。这就是序列优于自动增量列的原因。幸好您使用的是SQL Server。计算列比序列更灵活!我应该提到的是,我使用的是MSSQLS2000,我认为上面的方法不起作用,但我需要能够根据列的值,独立地增加数字,如果列包含“VAL1”,则分配2000000系列的表单号,如果列包含“VAL2”“然后从3000000系列中分配一个表单编号,但这些编号只有在分配后才会增加,因此我不会从每个系列中丢失编号。还有其他想法吗?感谢您指出这些问题,我决定不使用上面使用的触发器,我最终使用了表上的autoinc字段,并使用触发器通过添加200000或300000来更新应用程序编号,虽然这将在我的编号系统中产生间隙,但至少不会产生重复或错误的编号。