Sql 自动递增订单号(一个表中有多个公司)
我有一个主键OrderHeaderID,可以自动递增,但我还需要根据下订单的公司自动递增OrderNumber 当前策略:(在我的insert语句中) 问题:一旦我开始使用某些卷进行测试,我就开始出现重复的密钥错误: 表OrderHeader:Sql 自动递增订单号(一个表中有多个公司),sql,sql-server,auto-increment,Sql,Sql Server,Auto Increment,我有一个主键OrderHeaderID,可以自动递增,但我还需要根据下订单的公司自动递增OrderNumber 当前策略:(在我的insert语句中) 问题:一旦我开始使用某些卷进行测试,我就开始出现重复的密钥错误: 表OrderHeader: OrderHeaderID CompanyID OrderNumber 1 1 10000 2 1 10001 3 1 10002
OrderHeaderID CompanyID OrderNumber
1 1 10000
2 1 10001
3 1 10002
4 2 10000
5 2 10001
6 2 10002
要解决并发问题,您必须提高
SELECT
语句的隔离级别,然后在同一事务中执行INSERT
每个RBDM的具体语法都会有所不同,但下面是一个使用Sql Server的示例:
BEGIN TRANSACTION
DECLARE @OrderNumber INT
SELECT @OrderNumber = MAX(OrderNumber) + 1
FROM OrderHeader WITH (XLOCK)
WHERE CompanyID = @CompanyID
INSERT... (@OrderNumber)
COMMIT
这将对在
SELECT
语句期间读取的行设置独占锁,这将阻止此例程的另一个实例同时运行。相反,第二个实例将被阻止,直到原始进程执行插入
和提交
,此时第二个实例将继续读取并锁定新生成的值。请看我的回答:
出于您的目的,您可以这样定义公司表:
create table dbo.company
(
id int not null primary key ,
name varchar(32) not null unique ,
order_counter not null default(0) ,
...
)
create table dbo.order
(
company_id int not null foreign key references dbo.company( id ) ,
id int not null ,
order_number as 100000*company_id + id ,
...
constraint order_AK01 unique nonclustere ( order_number ) ,
constraint order_PK01 primary key clustered ( company_id , id ) ,
)
您的订单表如下:
create table dbo.company
(
id int not null primary key ,
name varchar(32) not null unique ,
order_counter not null default(0) ,
...
)
create table dbo.order
(
company_id int not null foreign key references dbo.company( id ) ,
id int not null ,
order_number as 100000*company_id + id ,
...
constraint order_AK01 unique nonclustere ( order_number ) ,
constraint order_PK01 primary key clustered ( company_id , id ) ,
)
并设置“添加订单”查询,如下所示:
declare @new_order_number int
update dbo.company
set @new_order_number = dbo.company.order_counter + 1 ,
order_counter = dbo.company.order_counter + 1
where dbo.company.id = @some_company_id
insert dbo.order ( company_id , id ) value ( @some_company_id , @new_order_number )
您没有并发(争用)条件:“互锁更新”会处理这个问题。此外,您还没有对数据库设计进行非规范化(第一种标准形式要求每一行和列的交集都是原子的/不可分解的:它只包含一个来自适用域的值,而不包含任何其他值。像您这样的复合标识符是多余的。)
轻松点 我将使用一个函数来自动增加每个给定ID的订单号 这是我在2分钟内完成的内容。它会满足你的要求
create table dbo.OrderHeader (
OrderHeader int identity(1,1) primary key
,CompanyID int
,OrderNumber int
)
go
create function dbo.NextOrderNumber (
@CompanyID int
)
returns int
as
begin
declare @result int;
select @result = OrderNumber + 1
from OrderHeader
where CompanyID = @CompanyID
if @result is null
set @result = 10000
return @result;
end
go
insert into OrderHeader select 1, dbo.NextOrderNumber(1)
insert into OrderHeader select 2, dbo.NextOrderNumber(1)
insert into OrderHeader select 2, dbo.NextOrderNumber(1)
insert into OrderHeader select 1, dbo.NextOrderNumber(1)
select *
from OrderHeader
您正在使用什么rdbms?sql server、mysql、oracle?为什么您希望订单号依赖于公司ID?我假设从他使用的SQL Server变量名。。。重新标记。谢谢,非常简单,没有任何架构更改!!此解决方案的问题在于它具有内置的竞争条件()。在UDF计算订单号和将该值插入表之间,另一个进程可以(并且在某个时候会)计算相同的订单号,并在进程完成插入之前将其插入表中。你会试图弄清楚为什么会出现看似随机的重复键错误(或者更糟的是,两个不同的顺序被合并成一个)。哦,我非常清楚这一点,也很清楚,这是本例答案的一半。事务和适当的隔离级别将是答案的其余部分,这显然是我的疏忽。