第一種實現流水號的方法:
注:取號全部在 RUL_Sequence 表中操作,不用管流水號所在表中的最大流水號
可以自由配置流水號規則。
前提:需要一個表和一個存儲過程。
表如下圖:
存儲過程如下:
- CREATE PROCEDURE [dbo].[Proc_GetSeqence]
- @SeqCode varchar(60), -- 規則代碼
- @ReturnNum Varchar(40) OUTPUT, -- 返回的流水號
- @MessageCode varchar(800) OUTPUT -- 異常消息等
- AS
- /* Exec Proc_GetSeqence 'OrderNo','',''
- *****************************************************************
- 作者: XXXXXXXXX
- 日期: 2013/06/30
- 功能描述: 獲取數據表的主鍵流水號(INV, ASN, SO...)
- 主要思路: 1.取得最新流水號信息
- 2.把所有固定的規則信息替換成具體值,其他保持不變
- eg:
- 規則為: ASN<YYYY><YY><MM><XXX>ASN
- 當前日期為: 20130630
- 當前流水號為:12
- 最終流水號為:ASN201306013ASN
- ******************************************************************
- */
- /*
- * SET NOCOUNT ON 的作用:
- * 不返回受影響行數
- * 存儲過程中包含的一些語句並不返回許多實際的數據,則該設置由於大量減少了網絡流量,因此可顯著提高性能。
- * */
- SET NOCOUNT ON
- DECLARE @SeqNowNumStr VARCHAR(20) --當前值字符類型
- DECLARE @SeqNowNum BIGINT --當前值
- DECLARE @year CHAR(4) --年 YYYY
- DECLARE @month CHAR(2) --月 MM
- DECLARE @day CHAR(2) --日 DD
- DECLARE @Length INT --流水號長度
- DECLARE @DataFormat VARCHAR(50) --流水號規則
- DECLARE @IniValue INT --歸零值
- DECLARE @ResetType VARCHAR(10) --歸零方式
- DECLARE @LastDate CHAR(8) --日期最大值
- DECLARE @WorkFLowStr VARCHAR(20) --前一次調用流水號時的日期值
- DECLARE @DataNow CHAR(8) --當前日期
- DECLARE @i INT --轉換變量,作用參照代碼上下文
- /*
- * SET XACT_ABORT ON 的作用:
- * 存儲中的某個地方出了問題,整個事務中的語句都會回滾
- * */
- SET XACT_ABORT ON
- BEGIN TRY
- /* 初始化變量 */
- SET @MessageCode='999'
- SET @ReturnNum = '0'
- SET @Length=0
- SET @SeqNowNum =0;
- SET @DataNow=CONVERT(CHAR(8),GETDATE(),112) --得到 20130704 的時間格式
- SET @year=SUBSTRING(@DataNow,1,4)
- SET @month =SUBSTRING(@DataNow,5,2)
- SET @day =SUBSTRING(@DataNow,7,2)
- Set @i=1
- /***********如果有並發的正在運行,最多等待0.06秒,然后繼續運行 Start*******/
- BEGIN TRANSACTION
- wait:
- Update dbo.RUL_Sequence Set [IsRunning]='2' where SeqCode=@SeqCode and IsRunning='1'
- If @@Rowcount=0
- Begin
- Waitfor Delay '00:00:01'
- Set @i=@i+1
- If @i<6 goto wait
- End
- COMMIT TRANSACTION
- /***********如果有並發的正在運行,最多等待0.06秒,然后繼續運行 End*******/
- Select @Length = [Length],@SeqNowNum=NowSeqValue,@LastDate=DateMax,@DataFormat=DataFormat
- ,@ResetType=ResetType,@IniValue =InitValue
- From RUL_Sequence where SeqCode=@SeqCode
- if @SeqNowNum=0 --當前值正常情況下不可能是0
- begin
- Set @MessageCode='100' --當前值 錯誤代碼
- select @MessageCode
- return
- END
- --@ResetType=1 不歸零 2 按日歸零 3 按月歸零 4按年歸零
- If (@ResetType=2 and @DataNow<>@LastDate AND @IniValue>0)
- OR (@ResetType=3 and @year+@month<>SUBSTRING(@LastDate,1,6) AND @IniValue>0)
- OR (@ResetType=4 and @year<>SUBSTRING(@LastDate,1,4) AND @IniValue>0 )
- BEGIN
- SET @SeqNowNum=@IniValue
- END
- SET @i=@Length --@i 此時表示流水號的總長度
- /***********拼流水號格式 Start*******/
- SET @WorkFLowStr='<'
- WHILE @Length>0
- BEGIN
- SET @WorkFLowStr=@WorkFLowStr+'X'
- SET @Length=@Length-1
- END
- SET @WorkFLowStr=@WorkFLowStr+'>'
- /***********拼流水號格式 End*******/
- set @SeqNowNumStr=CONVERT(VARCHAR(20),@SeqNowNum)
- SET @Length=@i-len(@SeqNowNumStr) --@Length 要補零的位數(eg:@SeqNowNumStr=148 當前流水號是五位,最后流水號為00148,00 就是需要補的兩位)
- /***********補零操作 Start*******/
- WHILE @Length>0
- BEGIN
- SET @SeqNowNumStr='0'+@SeqNowNumStr
- SET @Length=@Length-1
- END
- /***********補零操作 End*******/
- SET @ReturnNum=REPLACE( @DataFormat,'<YYYY>',@year); -- 把規則中<YYYY>替換成相應年
- SET @ReturnNum=REPLACE( @ReturnNum,'<MM>',@month); -- 把規則中<MM>替換成相應月
- SET @ReturnNum=REPLACE( @ReturnNum,'<DD>',@day); -- 把規則中<DD>替換成相應日
- SET @ReturnNum=REPLACE( @ReturnNum,@WorkFLowStr,@SeqNowNumStr);-- 把規則中的形如<XXX>的替換成相應流水號,
- /***********更新當前流水值為最大流水號、上一個流水號生成時間和運行標記(運行標記置為"1"(沒有運行) ) Start*******/
- Begin transaction
- UPDATE RUL_Sequence SET NowSeqValue=@SeqNowNum+1,DateMax=@DataNow,ISRUNNING='1', EditTime=Getdate()
- WHERE IsRunning='2' AND SeqCode=@SeqCode
- --SELECT * FROM RUL_Sequence WHERE IsRunning='2' AND SeqCode=@SeqCode
- -- PRINT @SeqNowNum+1
- Commit transaction
- /***********更新當前流水值為最大流水號、上一個流水號生成時間和運行標記(運行標記置為"1"(沒有運行) ) End*******/
- PRINT @ReturnNum
- RETURN
- END TRY
- --錯誤捕獲
- BEGIN CATCH
- ROLLBACK TRANSACTION
- set @MessageCode='行號='+cast(ERROR_LINE() as varchar(10))+'錯誤信息'+ERROR_MESSAGE()
- +'['+ERROR_PROCEDURE()+']'
- IF @@ROWcount<=0
- set @MessageCode='無此編號規則'+@MessageCode
- SELECT @MessageCode
- END CATCH
RUL_Sequence表中數據如圖:
執行存儲過程獲得流水號:
Exec Proc_GetSeqence 'OrderNo','',''
第二種實現流水號的方法:
注:取流水號所在表中的最大流水號 + 1
待研究問題:Shopping_Pay_Basic表中的流水號字段PayOrderNo遇到並發時,是否會影響用戶操作?
注:第一種實現只管取號,可能造成浪費,但沒有並發問題。
- --得到新編號的函數
- ALTER FUNCTION [dbo].[GetNextPayOrderNo](@Type char(2))
- RETURNS char(16)
- AS
- BEGIN
- DECLARE @dt CHAR(8)
- SELECT @dt=CONVERT(CHAR(8),GETDATE(),112)
- RETURN(
- SELECT @Type + (@dt+RIGHT(1000001+ISNULL(RIGHT(MAX(PayOrderNo),6),0),6))
- FROM Shopping_Pay_Basic WITH(XLOCK,PAGLOCK)
- WHERE PayOrderNo like @Type + @dt+'%')
- END
- -- SELECT dbo.GetNextPayOrderNo('TT')
執行函數獲得流水號:
- SELECT dbo.GetNextPayOrderNo('AA'