sqlserver之高靈活的業務單據流水號生成


最近的工作中要用到流水號,而且業務單據流水號生成的規則分好幾種,並非以前那種千篇一律的前綴+日期+流水號的簡單形式,經過對業務的分析,以及參考網上程序員的N種方法,整理出了一個表結構和存儲過程

思路分析:

1.大體上,流水號都遵循近似這樣的一般規則:流水號 = 前綴+動態內容+日期+中綴+流水號+后綴

   這里的動態內容是通過參數傳入流水號生成存儲過程的,比如動態內容為科室+組別,這個科室和組別是動態的,每一張單可能都不同,是根據登錄人組織信息得到的

2.流水號生成要控制並發

   並發的話,網上資料大多都是加鎖提示,比如holdlock,xlock,rowlock等等,但其它人又說最好不要加提示,鎖提示,索引提示能不加就不加,因為這個數據庫可以自動判斷,比如是鎖定整張表,還是鎖定某幾行等等,所以我直接設定了事務級別,我還是沒怎么搞清楚到底設置為repeatable read 還是 serializable,經過分析,個人認為還是設定為serializable,即串行化比較保險,相當於所有事務都按隊列進行,總是有排序的,但缺點是性能很差,當然也要看情況,一天幾張單,幾十張單,幾百張單就根本不用考慮性能問題了.如果是大型系統,估計也不是這樣搞法,至於大型系統是如何搞的,我真不知道(當然很想知道,比如淘寶,當當的訂單號是如何生成的???)

其它的還暫未想到,到時候碰到再更改,請各位同行們指點,以求改進

腳本代碼如下:

 

 

  1  --流水號表
  2  --流水號一般規則:流水號 = 前綴+動態內容+日期+中綴+流水號+后綴。
  3  --動態內容一般是執行存儲過程取流水號的時候動態傳入的
  4 if object_id('t_sequence_number') is not null
  5    drop table t_sequence_number
  6 go
  7  
  8 create table t_sequence_number(
  9   id int identity
 10  ,sequence_type varchar(50) not null                 --哪種類型的流水號,為求方便,默認是表名
 11  ,sequencenumber_len int  not null                   --流水號長度 如長度為4,表示'0000',長度為7,表示'0000000'等等
 12  ,reset_type varchar(50) not null                    --歸一類型,'year'表示按年,'month'表示按月,'day'表示按日,歸一類型與日期模板三個字段是有約束的,
如果是day,則年,月,日都不能為空,如果為month,則年月不能為空,如果為'',表示不要日期

13
,separator varchar(50) not null --流水號各部分分隔符 14 ,prefix varchar(50) not null --前綴 15 ,part_year_fmt varchar(50) not null --日期模板年份 可以是:yyyy,yy, 16 ,part_month_fmt varchar(50) not null --日期模板月份 可以是:mm,m等等 17 ,part_day_fmt varchar(50) not null --日期模板日期 可以是:dd,d等等 18 ,midfix varchar(50) not null --中綴 19 ,cur_max_sequence_number int not null --當前最大流水號值 20 ,cur_max_date datetime null --當前最大日期 21 ,suffix varchar(50) not null --后綴 22 23 ,constraint uq_t_sequence_number_sequence_type unique (sequence_type) 24 ,constraint pk_t_sequence_number_id primary key (id) 25 ,constraint chk_t_sequence_number_reset_type check (reset_type in ('year','month','day','')) 26 ,constraint chk_t_sequence_number_part_year_fmt check (part_year_fmt in ('yyyy','yy','')) 27 ,constraint chk_t_sequence_number_part_month_fmt check (part_month_fmt in ('mm','m','')) 28 ,constraint chk_t_sequence_number_part_day_fmt check (part_day_fmt in ('dd','d','')) 29 ,constraint chk_t_sequence_number_reset_type_map_fmt
check ( reset_type = ''
or charindex(left(reset_type,1),part_year_fmt+part_month_fmt+part_day_fmt)>0)
30
,constraint chk_t_sequence_number_cur_max_date check ( reset_type = ''
or (reset_type<>'' and cur_max_date is not null))
32 )
33 alter table t_sequence_number 34 add constraint def_t_sequence_number_sequencenumber_len default 4 for sequencenumber_len 35 36 alter table t_sequence_number 37 add constraint def_t_sequence_number_reset_type default ('day') for reset_type 38 39 alter table t_sequence_number 40 add constraint def_t_sequence_number_separator default ('') for separator 41 42 alter table t_sequence_number 43 add constraint def_t_sequence_number_prefix default ('') for prefix 44 45 alter table t_sequence_number 46 add constraint def_t_sequence_number_part_year_fmt default ('yyyy') for part_year_fmt 47 48 alter table t_sequence_number 49 add constraint def_t_sequence_number_part_month_fmt default ('mm') for part_month_fmt 50 51 alter table t_sequence_number 52 add constraint def_t_sequence_number_part_day_fmt default ('dd') for part_day_fmt 53 54 alter table t_sequence_number 55 add constraint def_t_sequence_number_midfix default ('') for midfix 56 57 alter table t_sequence_number 58 add constraint def_t_sequence_number_cur_max_sequence_number default (0) for cur_max_sequence_number 59 60 alter table t_sequence_number 61 add constraint def_t_sequence_number_cur_max_date default (getdate()) for cur_max_date 62 63 alter table t_sequence_number 64 add constraint def_t_sequence_number_suffix default ('') for suffix 65 66 go 67 68 if object_id('sp_Get_Sequence_Number') is not null 69 drop proc sp_Get_Sequence_Number 70 go 71 72 create procedure sp_Get_Sequence_Number 73 @sequence_type varchar(50) --流水號類別 74 ,@count int = 1 --獲取幾個序列號 75 ,@dynamic_content varchar(50) = '' --動態內容 76 as 77 begin 78 /* 79 --流水號一般規則:流水號 = 前綴+動態內容+日期+中綴+流水號+后綴。 80 --動態內容一般是執行存儲過程取流水號的時候動態傳入的 81 插入內容示例: 82 insert into t_sequence_number(sequence_type,sequencenumber_len,reset_type,separator,prefix,part_year_fmt,
part_month_fmt,part_day_fmt,midfix,cur_max_sequence_number,cur_max_date,suffix)
83 values('CarApply',4,'day','','LA','yy','mm','dd','',0,getdate(),'') 84 85 執行示例:exec sp_Get_Sequence_Number 'CarApply' 86 87 */ 88 set nocount on; 89 set transaction isolation level serializable; 90 91 declare @currentdate datetime 92 ,@sequencenumber_len int 93 ,@reset_type varchar(50) 94 ,@separator varchar(50) 95 ,@prefix varchar(50) 96 ,@part_year_fmt varchar(50) 97 ,@part_month_fmt varchar(50) 98 ,@part_day_fmt varchar(50) 99 ,@midfix varchar(50) 100 ,@cur_max_sequence_number int 101 ,@cur_max_sequence_number_firt_bak int 102 ,@cur_max_date datetime 103 ,@suffix varchar(50) 104 ,@datestr varchar(50); 105 106 declare @seqtable table(seqnum varchar(50),orderno int); 107 108 begin tran 109 110 --讀取配置信息 111 select @currentdate = getdate() 112 ,@sequencenumber_len = sequencenumber_len 113 ,@reset_type = reset_type 114 ,@separator = separator 115 ,@prefix = prefix 116 ,@part_year_fmt = part_year_fmt117 ,@part_month_fmt = part_month_fmt 118 ,@part_day_fmt = part_day_fmt 119 ,@midfix = midfix 120 ,@cur_max_sequence_number = cur_max_sequence_number 121 ,@cur_max_sequence_number_firt_bak = cur_max_sequence_number 122 ,@cur_max_date=cur_max_date 123 ,@suffix = suffix 124 ,@datestr = '' 125 from t_sequence_number where sequence_type=@sequence_type; 126 127 if @@rowcount = 0 128 begin 129 raiserror('無相應的流水號類別,請確認@sequence_type參數值是否正確!',16,1); 130 end 131 132 if @reset_type<>'' 133 begin 134 set @datestr = case @part_year_fmt
when 'yyyy' then cast(year(@currentdate) as varchar(50)) else right(cast(year(@currentdate) as varchar(50)),2) end 135 + case @part_month_fmt
when 'mm' then right('0'+ cast(month(@currentdate) as varchar(50)),2) else cast(month(@currentdate) as varchar(50)) end 136 + case @part_day_fmt
when 'dd' then right('0'+ cast(day(@currentdate) as varchar(50)),2) else cast(day(@currentdate) as varchar(50)) end 137 138 end 139 140 if convert(varchar(8), @currentdate, 112) = convert(varchar(8), @cur_max_date, 112) 141 set @cur_max_sequence_number = @cur_max_sequence_number + @count; --累加 142 else 143 begin 144 set @cur_max_sequence_number = 1; --歸1 145 set @cur_max_sequence_number_firt_bak = 0; 146 end 147 148 while @count >=1 149 begin 150 insert into @seqtable values( 151 @prefix 152 + @separator 153 + @dynamic_content 154 + case @dynamic_content when '' then '' else @separator end 155 + @datestr 156 + case @datestr when '' then '' else @separator end 157 + @midfix 158 + case @midfix when '' then '' else @separator end 159 + right( replicate('0',@sequencenumber_len)
+cast(@cur_max_sequence_number_firt_bak+@count as varchar(50)),@sequencenumber_len) 160 + case @suffix when '' then '' else @separator end 161 + @suffix 162 ,@count 163 ) 164 165 set @count = @count - 1; 166 167 end 168 169 update t_sequence_number 170 set cur_max_date = @currentdate 171 ,cur_max_sequence_number=@cur_max_sequence_number 172 where sequence_type=@sequence_type; 173 174 commit tran 175 176 --獲取流水號 177 select seqnum from @seqtable order by orderno asc 178 end

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM