熟悉仓库管理系统的人会比较清楚,系统中统有各种各样的单据,如补货单 、进货单、出库单等等。在这里,我们先介绍一种单据编码定义规则:
[仓库编码][单据类型][YYMMDD][4位流水号]
如:0101JH1202030001:
仓库编码:0101
单据类型:JH(进货)
生成日期:120203(12年02月03日)
四位流水:0001
上述规则是一种比较简单的编码方式,要注意的是上述的流水号在仓库、单据和日期之间不共享,即是说不同的仓库、不同的单据每天的流水号都是从1开始。
首先,我们采用一个表NoType,用来记录系统中的各种单据类型。
序号 |
列名 |
数据类型 |
长度 |
主键 |
允许空 |
默认值 |
说明 |
1 |
NoType |
varchar |
10 |
是 |
否 |
|
单据类型 |
2 |
NoTypeName |
nvarchar |
50 |
|
否 |
|
单据名称 |
然后,我们使用另一个表NoGenerate来记录每个仓库每种单据当日的最后生成的流水号。
序号 |
列名 |
数据类型 |
长度 |
主键 |
允许空 |
默认值 |
说明 |
1 |
Date |
nchar |
10 |
是 |
否 |
|
日期 |
2 |
NoType |
varchar |
10 |
是 |
否 |
|
类型 |
3 |
HouseCode |
varchar |
20 |
是 |
否 |
|
库房编号 |
4 |
LatestNo |
int |
4 |
是 |
否 |
((1)) |
最后流水号 |
使用Update更新方式
CREATE
PROCEDURE
[
dbo
].
[
ProcNoGenerateGet2
]
@NoType
VARCHAR(
10),
@HouseCode
VARCHAR(
20),
@length
INT,
@code
VARCHAR(
200) OUTPUT
AS
--
判断号码类型是否合法
IF
NOT
EXISTS (
SELECT
0
FROM NoType(NOLOCK)
WHERE NoType
=
@NoType )
BEGIN
SET
@code
=
'
0
'
RETURN
END
DECLARE
@LatestNo
INT
DECLARE
@date
NCHAR(
10)
SET
@date
=
CONVERT(
NCHAR(
10),
GETDATE(),
120)
UPDATE NoGenerate
SET
@LatestNo
=LatestNo
=LatestNo
+
1
WHERE Date
=
@date
AND NoType
=
@NoType
AND HouseCode
=
@HouseCode
IF (
@@rowcount
=
0)
BEGIN
INSERT
INTO NoGenerate (Date,NoType,HouseCode)
VALUES (
@Date,
@NoType,
@HouseCode)
SET
@latestNo
=
1
END
SET
@code
=dbo.NumberAddZeroPre(
@LatestNo,
@length)
SET
@code
=
@HouseCode
+
@NoType
+
SUBSTRING(
REPLACE(
@date,
'
-
',
''),
3,
6)
+
@code
其中,函数NumberAddZeroPre用来生成指定长度的流水号。
CREATE
FUNCTION
[
dbo
].
[
NumberAddZeroPre
] (
@num
INT,
@len
INT)
RETURNS
VARCHAR(
20)
AS
BEGIN
DECLARE
@str
VARCHAR(
20)
SET
@str
=
CAST(
@num
AS
VARCHAR)
DECLARE
@curLen
INT
SET
@curLen
=
LEN(
@str)
WHILE (
@curLen
<
@len)
BEGIN
SET
@str
=
'
0
'
+
@str
SET
@curLen
=
@curLen
+
1
END
RETURN
@str
END
使用Update方式进行单据号获取,足以满足大部情况的需求,但是在数据量和并发量大到一定程序的时候,会产生大量的数据锁,严重影响到系统性能,这时候,我们可以另一种解决方案,使用Insert方式实现流水号获取。
使用Insert插入方式
新建一表,定义主键时加上with(ignore_dup_key=on),忽略重复的记录。
1
CREATE
TABLE NoGenerate
2 (
3 Date
NCHAR(
10)
NOT
NULL,
4 NoType
VARCHAR(
10)
NOT
NULL,
5 HouseCode
VARCHAR(
20)
NOT
NULL,
6 LatestNo
INT
NOT
NULL
DEFAULT
1,
7
CONSTRAINT PK_NOGENERATE
PRIMARY
KEY (Date,NoType,HouseCode,LatestNo)
8 )
9
Go
新建一存储过程,采用插入的方式得到递增的流水号。
CREATE
PROCEDURE
[
dbo
].
[
ProcNoGenerateGet3
]
@NoType
varchar(
10),
@HouseCode
varchar(
20),
@length
int,
@code
varchar(
200) output
AS
--
判断号码类型是否合法
if
not
exists(
select
0
from NoType(nolock)
where NoType
=
@NoType)
begin
set
@code
=
'
0
'
return
end
--
当前日期、最大流水号、是否采号成功(:成功,:未成功)
declare
@date
int
=
cast(
Convert(
nchar(
8),
GetDate(),
112)
as
int)
declare
@dateS
nchar(
10)
=
Convert(
nchar(
10),
GetDate(),
120)
declare
@LatestNo
int
declare
@LatestNoOld
int
declare
@LatestDateForDel
int
=
0
declare
@LatestNoForDel
int
=
0
--
删除前一天的数据
if ((
select
count(
1)
from NoGenerateEx(nolock)
where NoType
=
@NoType
and HouseCode
=
@HouseCode)
>
1500)
begin
select
@LatestDateForDel
= T2.intDate,
@LatestNoForDel
= T2.LatestNo
from (
select
top
1 T1.
*
from (
select
top
1500 nge.intDate,nge.LatestNo
from NoGenerateEx nge(nolock)
where NoType
=
@NoType
and HouseCode
=
@HouseCode
order
by nge.intDate,nge.LatestNo
) T1
order
by t1.intDate
desc, T1.LatestNo
desc
) T2
delete
from NoGenerateEx
with(rowlock,xlock)
where
[
intDate
]
<
@LatestDateForDel
AND NoType
=
@NoType
and HouseCode
=
@HouseCode
delete
from NoGenerateEx
with(rowlock,xlock)
where
[
intDate
]
=
@LatestDateForDel
and LatestNo
<
@LatestNoForDel
AND NoType
=
@NoType
and HouseCode
=
@HouseCode
end
declare
@insertRe
smallint
=
0
while(
@insertRe
=
0)
BEGIN
set
@LatestNo
=
isnull((
select
max(LatestNo)
from NoGenerateEx(nolock)
where
[
intDate
]
=
@date
and NoType
=
@NoType
and HouseCode
=
@HouseCode),
0)
+
1
--
插入新号
insert
into NoGenerateEx(
[
intDate
],NoType,HouseCode,LatestNo)
values(
@date,
@NoType,
@HouseCode,
@LatestNo)
set
@insertRe
=
@@ROWCOUNT
end
--
返回值
set
@code
=
@HouseCode
+
@NoType
+right(
CAST(
@date
as
varchar(
8)),
6)
+dbo.NumberAddZeroPre(
@LatestNo,
@length)
采用此方式生成单据编码,与Update方式相比,会产生大量的数据,所以在存储过程中,需要不断的进行数据的清除,以保证性能,但是在并发比较高的情况下,优点也很明显,由于采用了Insert操作,所以不会出现锁表的现象。
指定长度流水号生成参考:http://www.cnblogs.com/wych/archive/2009/08/06/1540302.html