zoukankan      html  css  js  c++  java
  • 单据号生成

    熟悉仓库管理系统的人会比较清楚,系统中统有各种各样的单据,如补货单 、进货单、出库单等等。在这里,我们先介绍一种单据编码定义规则:

    [仓库编码][单据类型][YYMMDD][4位流水号]

    如:0101JH1202030001

    仓库编码:0101

    单据类型:JH(进货)

    生成日期:120203(120203)

    四位流水: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(10NOT NULL,
    4     NoType VARCHAR(10NOT NULL,
    5     HouseCode VARCHAR(20NOT 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(),112as 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(1from 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 

  • 相关阅读:
    进程间通迅之消息队列
    进程间通讯之共享内存
    标准块CP功能实现
    标准字符cp功能
    文件cp功能
    jest 的 coverage 提示 unknown 的解决方案
    js中的相等
    getBoundingClientRect 和 requestAnimFrame 的polyfill
    设计模式(4): 给组件实现单独的store
    Vue项目移动端滚动穿透问题
  • 原文地址:https://www.cnblogs.com/wych/p/2337390.html
Copyright © 2011-2022 走看看