熟悉仓库管理系统的人会比较清楚,系统中统有各种各样的单据,如补货单 、进货单、出库单等等。在这里,我们先介绍一种单据编码定义规则:
[仓库编码][单据类型][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更新方式
@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用来生成指定长度的流水号。
RETURNS VARCHAR(20)
AS
BEGIN
DECLARE @str VARCHAR(20)
SET @str=CAST(@num AS VARCHAR)
DECLARE @curLen INT
SET @curLen=LEN(@str)
WHILE (&#64;curLen < &#64;len)
BEGIN
SET &#64;str&#61;&#39;0&#39;&#43;&#64;str
SET &#64;curLen&#61;&#64;curLen&#43;1
END
RETURN &#64;str
END
使用Update方式进行单据号获取&#xff0c;足以满足大部情况的需求&#xff0c;但是在数据量和并发量大到一定程序的时候&#xff0c;会产生大量的数据锁&#xff0c;严重影响到系统性能&#xff0c;这时候&#xff0c;我们可以另一种解决方案&#xff0c;使用Insert方式实现流水号获取。
使用Insert插入方式
新建一表&#xff0c;定义主键时加上with(ignore_dup_key&#61;on)&#xff0c;忽略重复的记录。
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
新建一存储过程&#xff0c;采用插入的方式得到递增的流水号。
&#64;NoType varchar(10),
&#64;HouseCode varchar(20),
&#64;length int,
&#64;code varchar(200) output
AS
--判断号码类型是否合法
if not exists(select 0 from NoType(nolock) where NoType&#61;&#64;NoType)
begin
set &#64;code&#61;&#39;0&#39;
return
end
--当前日期、最大流水号、是否采号成功&#xff08;&#xff1a;成功&#xff0c;&#xff1a;未成功&#xff09;
declare &#64;date int &#61; cast(Convert(nchar(8),GetDate(),112) as int)
declare &#64;dateS nchar(10) &#61; Convert(nchar(10),GetDate(),120)
declare &#64;LatestNo int
declare &#64;LatestNoOld int
declare &#64;LatestDateForDel int &#61; 0
declare &#64;LatestNoForDel int &#61; 0
--删除前一天的数据
if ((select count(1) from NoGenerateEx(nolock) where NoType &#61; &#64;NoType and HouseCode &#61; &#64;HouseCode)> 1500)
begin
select &#64;LatestDateForDel &#61; T2.intDate, &#64;LatestNoForDel &#61; T2.LatestNo from (
select top 1 T1.* from (
select top 1500 nge.intDate,nge.LatestNo from NoGenerateEx nge(nolock)
where NoType &#61; &#64;NoType and HouseCode &#61; &#64;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] < &#64;LatestDateForDel AND NoType &#61; &#64;NoType and HouseCode &#61; &#64;HouseCode
delete from NoGenerateEx with(rowlock,xlock) where [intDate] &#61; &#64;LatestDateForDel and LatestNo < &#64;LatestNoForDel AND NoType &#61; &#64;NoType and HouseCode &#61; &#64;HouseCode
end
declare &#64;insertRe smallint &#61; 0
while(&#64;insertRe &#61; 0)
BEGIN
set &#64;LatestNo &#61; isnull((select max(LatestNo) from NoGenerateEx(nolock)
where [intDate] &#61; &#64;date and NoType &#61; &#64;NoType and HouseCode &#61; &#64;HouseCode),0) &#43; 1
--插入新号
insert into NoGenerateEx([intDate],NoType,HouseCode,LatestNo)values(&#64;date,&#64;NoType,&#64;HouseCode,&#64;LatestNo)
set &#64;insertRe&#61;&#64;&#64;ROWCOUNT
end
--返回值
set &#64;code &#61; &#64;HouseCode&#43;&#64;NoType&#43;right(CAST(&#64;date as varchar(8)),6)&#43;dbo.NumberAddZeroPre(&#64;LatestNo,&#64;length)
采用此方式生成单据编码&#xff0c;与Update方式相比&#xff0c;会产生大量的数据&#xff0c;所以在存储过程中&#xff0c;需要不断的进行数据的清除&#xff0c;以保证性能&#xff0c;但是在并发比较高的情况下&#xff0c;优点也很明显&#xff0c;由于采用了Insert操作&#xff0c;所以不会出现锁表的现象。
指定长度流水号生成参考&#xff1a;http://www.cnblogs.com/wych/archive/2009/08/06/1540302.html