Sql 如何在一个表中使用多个标识号?
我有一个创建可打印表单的web应用程序,这些表单上有一个唯一的编号,问题是我有两个表单,需要为它们创建单独的编号。 (工业工程) 表格1-编号2000000-299999Sql 如何在一个表中使用多个标识号?,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系列号),然后我创建了一个触
表格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
justINSERT 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来更新应用程序编号,虽然这将在我的编号系统中产生间隙,但至少不会产生重复或错误的编号。