Sql Server 2008中如何实现一个产生全局的不重复的自增ID?类似于Oracle的序列功能

时间:2021-11-11 00:45:40
看到这个标题,有人可能会说用sqlserver的自增ID就行了,但是现在我遇到的问题自增ID解决不了,因为它只能保证在同一个表中自增且不重复,多个表就就必须从头开始

我需要实现一个全局的自增ID,就像Oracle的序列一样,多个表的ID都取自这个序列,多个表的ID必须不能重复


有人研究过吗?

15 个解决方案

#1


uniqueidentifier
全局唯一标识符 (GUID)。

注释
uniqueidentifier 数据类型的列或局部变量可用两种方法初始化为一个值: 

使用 NEWID 函数。


将字符串常量转换为如下形式(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字)。例如,6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 uniqueidentifier 值。 
比较运算符可与 uniqueidentifier 值一起使用。然而,排列并非通过比较两个值的位模式来实现。允许对 uniqueidentifier 值执行的操作只有比较 (=, <>, <, >, <=, >=) 和检查 NULL(IS NULL 和 IS NOT NULL)。不允许使用其它算术运算符。所有的列约束及属性(IDENTITY 除外)均允许用于 uniqueidentifier 数据类型。 

#2


引用 1 楼 dawugui 的回复:
uniqueidentifier
全局唯一标识符 (GUID)。

注释
uniqueidentifier 数据类型的列或局部变量可用两种方法初始化为一个值: 

使用 NEWID 函数。


将字符串常量转换为如下形式(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字)。例如,6F9619……
+1

#3


mark

#4


忘了说明了,放弃GUID这种方式,因为GUID太长,识别太困难,而且数据大的时候,GUID太占资源,远不如int来得高效

#5


引用 4 楼 hjl425 的回复:
忘了说明了,放弃GUID这种方式,因为GUID太长,识别太困难,而且数据大的时候,GUID太占资源,远不如int来得高效
不用GUID,那sql server就没有你说的oracle的序列功能.

#6


用SQL的话,可以写个function来实现,具体怎么写就看你自己的实际需求了,一般情况下都是取MAX(id),然后+1

#7


写一个函数就可以了 

参考 :


在学习中遇到这个问题 
数据库里有编号字段 
BH00001 
BH00002 
BH00003 
BH00004 
如何实现自动增长

 

--下面的代码生成长度为8的编号,编号以BH开头,其余6位为流水号。
--得到新编号的函数
CREATE FUNCTION f_NextBH()
RETURNS char(8)
AS
BEGIN
    RETURN(SELECT 'BH'+RIGHT(1000001+ISNULL(RIGHT(MAX(BH),6),0),6) FROM tb WITH(XLOCK,PAGLOCK))
END
GO

--在表中应用函数
CREATE TABLE tb(
BH char(8) PRIMARY KEY DEFAULT dbo.f_NextBH(),
col int)

--插入资料
BEGIN TRAN
    INSERT tb(col) VALUES(1)
    INSERT tb(col) VALUES(2)
    INSERT tb(col) VALUES(3)
    DELETE tb WHERE col=3
    INSERT tb(col) VALUES(4)
    INSERT tb(BH,col) VALUES(dbo.f_NextBH(),14)
COMMIT TRAN

--显示结果
SELECT * FROM tb
/*--结果
BH         col 
---------------- ----------- 
BH000001  1
BH000002  2
BH000003  4
BH000004  14
--*/

 

create table tb
(id int identity,
name varchar(10),
code as 'BH'+right('0000'+cast(id as varchar),5))
go
insert tb(name) select 'A'
union all select 'B'
union all select 'C'
union all select 'D'

select * from tb

drop table tb

/*
id          name       code         
----------- ---------- ------------ 
1           A          BH00001
2           B          BH00002
3           C          BH00003
4           D          BH00004

(所影响的行数为 4 行)
*/

#8


引用 6 楼 aday 的回复:
用SQL的话,可以写个function来实现,具体怎么写就看你自己的实际需求了,一般情况下都是取MAX(id),然后+1



这种方式基本不可行,经过测试,在多并发的时候,比如极短时间之内很多用户一起添加记录的时候,很容易就导致两条记录的ID是一样的

#9


1.不要使用 GUID ,这东西一旦在主键/索引的位置,对性能的影响非常大.
2.建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

#10


引用 9 楼 mstop 的回复:
建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

同上

#11


create table Seq(ID bigint)
insert Seq select 0

--提取新序列
declare @ID as bigint
update seq set @id=id=id+1
select @id

#12


引用 10 楼 jalor_6 的回复:
引用 9 楼 mstop 的回复:

建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

同上



是个不错的方案,我想的在库中新建一个序列表,设定一个自增字段,其它的表中新建记录的时候先往序列表中插入一条记录并同时获取最新ID,将这个ID写入其它的表中(在事务中处理),我想这样应该可以曲线实现类似于Oracle的序列功能了

另外,序列表只是起产生一个新ID的作用,可以定期将及清空

#13


GUID

#14


可以用一张表来体现这个内容

例如 表 A 里面 a 字段表示全局id

当你在一个表插入一条信息的时候,那你就重表A  中 获取 这个id,然后在改变表 A 中的 a 的值,这样就保证,主键不重复了

#15


感谢大家的参与,已经找到问题的解决办法,谢谢大家,结帖了

#1


uniqueidentifier
全局唯一标识符 (GUID)。

注释
uniqueidentifier 数据类型的列或局部变量可用两种方法初始化为一个值: 

使用 NEWID 函数。


将字符串常量转换为如下形式(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字)。例如,6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 uniqueidentifier 值。 
比较运算符可与 uniqueidentifier 值一起使用。然而,排列并非通过比较两个值的位模式来实现。允许对 uniqueidentifier 值执行的操作只有比较 (=, <>, <, >, <=, >=) 和检查 NULL(IS NULL 和 IS NOT NULL)。不允许使用其它算术运算符。所有的列约束及属性(IDENTITY 除外)均允许用于 uniqueidentifier 数据类型。 

#2


引用 1 楼 dawugui 的回复:
uniqueidentifier
全局唯一标识符 (GUID)。

注释
uniqueidentifier 数据类型的列或局部变量可用两种方法初始化为一个值: 

使用 NEWID 函数。


将字符串常量转换为如下形式(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字)。例如,6F9619……
+1

#3


mark

#4


忘了说明了,放弃GUID这种方式,因为GUID太长,识别太困难,而且数据大的时候,GUID太占资源,远不如int来得高效

#5


引用 4 楼 hjl425 的回复:
忘了说明了,放弃GUID这种方式,因为GUID太长,识别太困难,而且数据大的时候,GUID太占资源,远不如int来得高效
不用GUID,那sql server就没有你说的oracle的序列功能.

#6


用SQL的话,可以写个function来实现,具体怎么写就看你自己的实际需求了,一般情况下都是取MAX(id),然后+1

#7


写一个函数就可以了 

参考 :


在学习中遇到这个问题 
数据库里有编号字段 
BH00001 
BH00002 
BH00003 
BH00004 
如何实现自动增长

 

--下面的代码生成长度为8的编号,编号以BH开头,其余6位为流水号。
--得到新编号的函数
CREATE FUNCTION f_NextBH()
RETURNS char(8)
AS
BEGIN
    RETURN(SELECT 'BH'+RIGHT(1000001+ISNULL(RIGHT(MAX(BH),6),0),6) FROM tb WITH(XLOCK,PAGLOCK))
END
GO

--在表中应用函数
CREATE TABLE tb(
BH char(8) PRIMARY KEY DEFAULT dbo.f_NextBH(),
col int)

--插入资料
BEGIN TRAN
    INSERT tb(col) VALUES(1)
    INSERT tb(col) VALUES(2)
    INSERT tb(col) VALUES(3)
    DELETE tb WHERE col=3
    INSERT tb(col) VALUES(4)
    INSERT tb(BH,col) VALUES(dbo.f_NextBH(),14)
COMMIT TRAN

--显示结果
SELECT * FROM tb
/*--结果
BH         col 
---------------- ----------- 
BH000001  1
BH000002  2
BH000003  4
BH000004  14
--*/

 

create table tb
(id int identity,
name varchar(10),
code as 'BH'+right('0000'+cast(id as varchar),5))
go
insert tb(name) select 'A'
union all select 'B'
union all select 'C'
union all select 'D'

select * from tb

drop table tb

/*
id          name       code         
----------- ---------- ------------ 
1           A          BH00001
2           B          BH00002
3           C          BH00003
4           D          BH00004

(所影响的行数为 4 行)
*/

#8


引用 6 楼 aday 的回复:
用SQL的话,可以写个function来实现,具体怎么写就看你自己的实际需求了,一般情况下都是取MAX(id),然后+1



这种方式基本不可行,经过测试,在多并发的时候,比如极短时间之内很多用户一起添加记录的时候,很容易就导致两条记录的ID是一样的

#9


1.不要使用 GUID ,这东西一旦在主键/索引的位置,对性能的影响非常大.
2.建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

#10


引用 9 楼 mstop 的回复:
建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

同上

#11


create table Seq(ID bigint)
insert Seq select 0

--提取新序列
declare @ID as bigint
update seq set @id=id=id+1
select @id

#12


引用 10 楼 jalor_6 的回复:
引用 9 楼 mstop 的回复:

建立一个表,用于记录当前ID,写一个储存过程,专门读这个ID,累加后回写该表,并反回ID值.(要用事务)

同上



是个不错的方案,我想的在库中新建一个序列表,设定一个自增字段,其它的表中新建记录的时候先往序列表中插入一条记录并同时获取最新ID,将这个ID写入其它的表中(在事务中处理),我想这样应该可以曲线实现类似于Oracle的序列功能了

另外,序列表只是起产生一个新ID的作用,可以定期将及清空

#13


GUID

#14


可以用一张表来体现这个内容

例如 表 A 里面 a 字段表示全局id

当你在一个表插入一条信息的时候,那你就重表A  中 获取 这个id,然后在改变表 A 中的 a 的值,这样就保证,主键不重复了

#15


感谢大家的参与,已经找到问题的解决办法,谢谢大家,结帖了