在項目中,大家可能都遇到過,需要把十進位轉換為其他進位的情況,google上一搜,已經有很多2進位、8進位、16進位和十進位的轉換方法。但是在一些項目中,這些可能無法滿足要求,可能需要17、18甚至是32、36進位和十進位的轉換,那麼我們應該怎麼辦呢?不可能為每一種進位都去寫一個函數,那樣可不是明智之舉。所以我這裡提供一個十進位與N進位之間的互轉函數(N<=32)。
N進位函數1、準備工作
在寫N進位函數之前,需要有一個用於儲存表示N進位字元的基礎資料表,這裡我用一個表函數表示:
CREATE FUNCTION xavi.fn_NSystemTable()RETURNS @temp TABLE (id SMALLINT IDENTITY, [Char] CHAR(1),[Ascii] SMALLINT)ASBEGIN DECLARE @ignoreAscii TABLE ([Ascii] SMALLINT) DECLARE @i INT SET @i = 58 WHILE(@i <= 64) BEGIN INSERT INTO @ignoreAscii VALUES (@i) SET @i = @i + 1 END SET @i = 0 WHILE(@i < 43) BEGIN IF NOT EXISTS (SELECT 1 FROM @ignoreAscii WHERE [Ascii] = @i + 48) BEGIN INSERT INTO @temp VALUES (CHAR(@i + 48),@i + 48) END SET @i = @i + 1 END RETURNEND
2、十進位轉換為N進位
CREATE FUNCTION xavi.fn_DecimalToNSystem (@bigInt BIGINT, @n TINYINT)RETURNS VARCHAR(100)AS BEGIN Declare @result VARCHAR(100),@mode INT,@remainder INT, @iRet CHAR(1) SELECT @mode = @bigInt, @result = '' WHILE(1 = 1) BEGIN IF(@bigInt = 0 OR @n = 0 OR @n = 1) BEGIN SET @result = CONVERT(VARCHAR(100),@bigInt) BREAK END IF(@mode = 0) BEGIN BREAK END SET @remainder = @mode % @n SET @mode = @mode / @n SELECT @iRet = [Char] FROM xavi.fn_NSystemTable() ns WHERE ns.id = @remainder + 1 SET @result = @iRet + @result END RETURN @resultEND
3、N進位轉換為十進位
CREATE FUNCTION xavi.fn_NSystemToDecimal (@nSys VARCHAR(100), @n TINYINT)RETURNS BIGINTASBEGIN Declare @result int,@iPos int,@iTmp int Select @result = 0,@iPos = 0 While(@iPos < Len(@nSys)) BEGIN SELECT @iTmp = ns.id - 1 FROM xavi.fn_NSystemTable() ns WHERE ns.[Char] = SUBSTRING(@nSys,LEN(@nSys) - @iPos,1) Set @result = @result + @iTmp * POWER(CAST(@n AS BIGINT),cast(@iPos AS BIGINT)) Set @iPos = @iPos + 1 END RETURN @resultEND
注意:目前測試下來對於最高進位(36進位),最多支援13位,但是我想這也足夠了,因為36進位所能表示的範圍遠比10進位的13位元大得多,0<=y<=36 * 3612 + 36 * 3611 +......+ 36 * 361 + 36。所以一個N進位來說能表示的範圍應該為:0<=y<=N * Nx + N * Nx-1 +......+ N * N1 + N。
如何使用
那麼我們應該怎麼使用這些函數呢,這裡舉一個自增36進位欄位的表的例子。
首先建立一個表:
CREATE TABLE xavi.tb_Test( ID CHAR(10) PRIMARY KEY, Account VARCHAR(20), [Name] NVARCHAR(10))
然後建立一個觸發器:
CREATE TRIGGER xavi.tr_TestInsertON xavi.tb_TestINSTEAD OF INSERT ASSET NOCOUNT ONDECLARE @maxID BIGINT, @n TINYINT, @nSystemChar VARCHAR(10)SET @n = 36SELECT @maxID = ISNULL(MAX(xavi.fn_NSystemToDecimal(ID,@n)),0) FROM xavi.tb_TestSET @nSystemChar = xavi.fn_DecimalToNSystem(@maxID + 1, @n)INSERT INTO xavi.tb_Test(ID,Account,[Name])SELECT REPLICATE('0',10 - LEN(@nSystemChar)) + @nSystemChar, Account, [Name]FROM INSERTED
接著往這個表裡插入100條冊數資料:
DECLARE @i INTSET @i = 1WHILE(@i <= 100)BEGIN INSERT INTO xavi.tb_Test VALUES(@i,LEFT(REPLACE(CONVERT(VARCHAR(100),NEWID()),'-',''),10),LEFT(REPLACE(CONVERT(VARCHAR(100),NEWID()),'-',''),10)) SET @i = @i + 1END
執行看下錶裡的資料,可以得到如的結果:
從這個結果應該可以觀察到,ID這一列已經是36進位的表示形式了。
擴充用法
有了這個N進位函數,那麼我們再生產一些唯一編碼、訂單號等一些編碼時,就可以用更少的位元,表示更大的範圍。