[心得]群裡提問的流水序號產生方式

在群裡有天@潇湘隐者 提了一個這樣的問題,蠻有趣的。當天就試了一下 以下是我的思路跟測試語法

-------------------------------------------------------

有这样一个需求需要根据输入的编码(这个编码值来自于数据库的一个表)生成下一个编码,编码规则如下所示(我们暂且不关心这个逻辑是否合理,只关心如何实现):

1: 最小值为A0000, 最大值为ZZZZZ

2:编码A0000的下一个值为A0001, 编码A9999的下一个值为B0000, 编码AB999的下一个值为AC000,编码AC999的下一个值为AD000,依此内推。

3:不用担心输入值为A09BC这种值,应用程序从表里面取编码的最大值。应用程序会检查、控制输入参数,不用在数据库的函数里面做检查控制。

4:不用担心输入值为ac908这种值(大小写问题),应用程序从表里获取编码的值(不接受用户输入)。所以这个检查、控制也不用纳入数据库函数考虑范围。

---------------------------------------------------

以下是我寫的解法,適用於SQL Server 2008 R2 +  (倒是沒在其它版本試過,不過Oracle我查了一下有相對應的函數。應該可以無痛切換)

CREATE FUNCTION [dbo].[GeneratorKey]
(
	-- Add the parameters for the function here
	@Serial VARCHAR(5)
)
RETURNS VARCHAR(5)
AS
BEGIN
	DECLARE @Header VARCHAR( 5) =‘‘; --頭編號
	DECLARE @Number VARCHAR( 4)=‘‘ ; -- 尾編號
	DECLARE @FullNumber VARCHAR( 5)=‘‘ ;
	DECLARE @ADD_RANGE int= 1;
--拆分傳入值為頭(字母 ) 尾( 數字)
	WHILE((ASCII (CAST( @Serial as CHAR)))>= 65)
	BEGIN
		 SET @[email protected] +SUBSTRING( @Serial,1 ,1);
		 SET @Serial=SUBSTRING (@Serial, 2,LEN (@Serial)- 1)
	END
	--這裡@Serial 會只存放截出的[數字],但因為下面計算@Serial實際的長度
	--需要用到原始數字的長度,所以多一個@Number來做存放
	SET @Number = @Serial;
--拆分結束
	--開始進行編號+1動作
	IF CAST (@Number as int)=CAST (REPLICATE( ‘9‘,LEN (@Number)) AS INT) --當編號準備要進位時
	BEGIN
		 IF ASCII(CAST (SUBSTRING( @Header,LEN (@Header), 1) as CHAR ))=90 -- 判斷目前最大英文是否到 Z
		 BEGIN
			SET @Header = @Header+‘A‘
		 END
		 ELSE -- 如果沒有到 Z則英文數字就進位
		 BEGIN
			SET @Header = SUBSTRING(@Header ,1, LEN(@Header )-1) + CHAR(ASCII (CAST( SUBSTRING(@Header ,LEN( @Header),1 ) as CHAR))+ 1)
		 END
	SET @Number =REPLICATE( ‘0‘,LEN (@Number))
	SET @FullNumber [email protected]+ @Number; --設定最新流水號
	END
	ELSE
	BEGIN
		 SET @Number =CAST( @Number as int)+ 1;
		 --這裡就需要依照@Serial實際的長度來補多少個
		 --因為@Number 轉成int後就會去掉零
		 SET @Number = REPLICATE(‘0‘ ,LEN( @Serial)-LEN (@Number)) + @Number -- 補
		 SET @FullNumber [email protected]+ @Number; --設定最新流水號
	END
	--PRINT @FullNumber
	RETURN @FullNumber

END

  

流程大致是這樣的

1.我們將編號拆分成頭編號(英文)與尾編號(數字)分別存放,最後再合併成為一個完整的流水號

2.在14行我們做了將傳入的編號,拆分成頭編號與尾編號的動作。這裡就利用到ASCII函數永遠只會取第一碼的特性。假設傳入的是A0001就會回傳65,B0001則是66

所以我們可以永遠判斷第一位的ASCII碼是不是英文字母,是的話就截出來放入頭編號中。然後留下後續的字串符再重複做。直到沒有英文字母為止

3.因為我們編號已經拆為頭尾了,所以就很容易做相加的動作(因為我們要取得下一位的流水號)

首先我們判斷尾編號是否已經要進位了 (比如說9999或999或99這種,就是要進位了) 如果是的話就要做進位的動作

進位的動作是這樣的,我們要判斷的是目前最大的英文是否到Z如果是到Z了,就要補上新的頭編號。 e.g.   Z9999 下一位會是ZA000

如果還沒有到Z就將目前最大的英文做進位的動作,e.g.  A9999 -> B0000 。至於怎麼取最大的英文可以參考26行SUBSTRING的寫法

4.如果不需要進位的話,就簡單的將尾編號做加1的動作,都做完後就可以準備組成我們下一個流水號了。 這裡我用了一個REPLICATE函數,他可以依照你設定的值,重複某一段文字

補零的動作其實就是找出我們原本傳入的尾編號長度,再扣掉我們運算後的尾編號長度。之所以要做這個動作是因為當我們將 ‘0001‘這個編號轉成int做加1後,會變成2。原本的000就消失了

所以我們利用,原本的尾編號長度(0001) 扣掉我們運算後的尾編號長度(1) 。就知道我們需要重複3個0。

最後是我簡單的測試語法 :)

DECLARE @Serial VARCHAR( 5)=‘ZA000‘ --啟始的編號
DECLARE @Header VARCHAR( 5)=‘‘
DECLARE @Count int= 50000; --要產生多少筆流水號
WHILE(@Count !=0)
BEGIN
        SELECT @Serial=dbo.GeneratorKey( @Serial);
        PRINT @Serial ;
        SET @Count [email protected] 1;
END

總結,我的思路是這樣的,透過英文可以轉成對應的ASCII碼,其實就可以利用ASCII碼做相加的動作。得到我們下一個要用到的英文字母

e.g. A的ASCII碼為65 ,我們可以先轉成65後做相加變成66,最後再轉回來英文字母,就會變成B  :D

數字的部分就單純的拆解出來做相加就好了。

這裡有趣的地方是T-SQL ASCII這個函數不管你傳入多長的字串,他永遠只會回傳第一個字母的ASCII碼,這特性剛好讓我拿來做字母與數字拆分的動作 :D

有興趣的朋友可以協助測試唷!

时间: 2024-10-18 10:38:03

[心得]群裡提問的流水序號產生方式的相关文章

[zz]提問的智慧

提問的智慧 How To Ask Questions The Smart Way Copyright © 2001,2006,2014 Eric S. Raymond, Rick Moen 本指南英文版版權為 Eric S. Raymond, Rick Moen 所有. 原文網址:http://www.catb.org/~esr/faqs/smart-questions.html Copyleft 2001 by D.H.Grand(nOBODY/Ginux), 2010 by Gasolin,

[转帖] 提問的智慧

[原文转自鸟哥http://phorum.vbird.org/viewtopic.php?t=96] 在黑客世界,當提出一個技術問題時,你能得到怎樣的回答? 這取決於挖出答案的難度,同樣取決於你提問的方法. 本指南旨在幫助你提高發問技巧,以獲取你最想要的答案. 首先你必須明白,黑客們只偏愛艱巨的任務,或者能激發他們思維的好問題. 如若不然,我們還來幹嗎?如果你有值得我們反復咀嚼玩味的好問題, 我們自會對你感激不盡.好問題是激勵,是厚禮,可以提高我們的理解力, 而且通常會暴露我們以前從沒意識到或者

Others # 看到的一些創意 / 知乎不錯的提問/ Android安全

創意 http://blog.sina.com.cn/s/blog_966fb2d30101d93s.html 體重數據同步手機上,隨時查看 http://www.zhihu.com/question/24004857/answer/26455139 脸萌討論 http://www.wandoujia.com/apps/com.covworks.uface Uface面部素描 Android版 http://www.xpgod.com/soft/9187.html Uface PC版 http:

二叉树基本操作:前序、中序、后序遍历(递归方式)

二叉树是最常见最重要的数据结构之一,它的定义如下: 二叉树(binary tree)是有限多个节点的集合,这个结合或者是空集,或者由一个根节点和两颗互不相交的.分别称为左子树和右子树的二叉树组成. 二叉树最基本的操作是遍历:一般约定遍历时左节点优先于右节点,这样根据根节点的遍历顺序可分为三种遍历操作:前序-先遍历根节点,再处理左右节点:中序-先遍历左节点,然后处理根节点,最后处理右节点:后序-先遍历左右节点,然后处理根节点. 从上边二叉树定义可以看出:二叉树使用了递归的概念描述.所以,二叉树的很

关于hadoop2.x(2.7.1 2.7.2)集群配置和测试运行中Ubuntu虚拟机VM设置nat方式导致节点传输问题

集群配置都大同小异,在这里我简单说下我的配置: 主节点系统是Ubuntu 14.04 LTS x64其他两个节点在VM中系统为Centos 6.4 x64 JVM为jdk1.7_80 hadoop版本2.7.1和2.7.2都尝试了 出现的问题是: 启动hdfs系统正常,都启动起来了,jps查看如下 主节点 SecondaryNameNode和 NameNode 从节点:DataNode 但使用hfds命令dfsadmin -report发现live的datanode只有1个,而且当你不同时间re

集群环境中使用Redis实现分布式锁两种方式

一.介绍 互联网的应用场景中,为了支持高并发的请求,服务都是执行的分布式部署,相同的任务可以在集群中不同的服务器上执行,并且现在的服务容器都是支持多线程,相同的任务也可能会被同一个容器多次执行,都要求执行结果都满足幂等性的设计原则. 分布式锁,就是为了确保在分布式的环境下,相同任务只会执行成功的执行一次,后续的执行不会对这些已经产生了变化的业务再次产生影响. 分布式锁的实现有不少的方式,如: 使用RDBMS数据库本身的表锁或行锁特性: 使用Redis做为分布式锁: 使用Zookeeper做为分布

[亂數] <細說> C/C++ 亂數基本使用與常見問題

陸陸續續寫了 EA  一.二年,以前亂數引導文回頭看時才發現,怎麼有這麼多細節的錯誤.沒系統. 這篇文章主要引導初學者使用亂數,同時附上常被翻出來討論的議題,C/C++適用,唯以 C 語言撰之. 也由於是引導初學者,所以在某些用詞上會較不正確, 像 compiler.IDE 會故意混為一談. 另外亂數原理也全都跳過 < 重點是亂數的產生原理也不只一種 >. 另本文附程式碼,不附執行結果,有興趣自己跑一遍. 最後請注意本文在區間表達裡,開區間與閉區間 括號的使用,也就是, [a, b]  ,  

MATLAB统计与回归

11.1 前言 統計的技巧與資料分析常常形影不離.一般統計使用加法.累加法.平均值,中間值等等,由於處理的對象是矩陣資料,故其基本統計之技巧已經廣為應用,其觀念也會在正常之運作中出現.統計學中比較特殊應用者為機率.亂數.常態分配等,而配合應用者為其相關之圖表. 在MATLAB中,有一個統計學工具箱,內藏各種統計學上需要應用的指令,可以執行上述與統計學有關之內容.這些相關的指令大部份以M-檔案組成,所以可利用type 這個功能檢視其內容.甚至可以更改其檔案名稱與內容,增加自己需要的功能,使其成為新

SQL模擬死結產生

引用自:http://jengting.blogspot.tw/2012/06/sql.html 根據 MSDN 將死結數量降至最低 裡的圖型模擬死結產生 ~~ 在 SSMS 內開啟兩個 T-SQL 查詢(兩個執行緒),利用下面語法來執行,請先執行 T-SQL 查詢 1,再執行 T-SQL 查詢 2. 步驟簡易說明: Step 1:建立一個 T-SQL 查詢 1,開啟一個交易,並進行更新 Supplier 資料 Step 2:建立另一個 T-SQL 查詢 2,開啟一個交易,並進行更新 Part