2013-03-07 72 views
3

在我們的數據庫中,我們使用主鍵作爲數字0到9以及字母表中所有不是誓言的字母的組合。包括字母Y. 我創建了這個表來組織它。在SQL Server中將Base 31的值轉換爲BigInt

CREATE Table Base31 
(ID varchar(1), 
NumberValue bigint) 

GO 

Insert into Base31 SELECT '0', '0' 
Insert into Base31 SELECT '1', '1' 
Insert into Base31 SELECT '2', '2' 
Insert into Base31 SELECT '3', '3' 
Insert into Base31 SELECT '4', '4' 
Insert into Base31 SELECT '5', '5' 
Insert into Base31 SELECT '6', '6' 
Insert into Base31 SELECT '7', '7' 
Insert into Base31 SELECT '8', '8' 
Insert into Base31 SELECT '9', '9' 
Insert into Base31 SELECT 'B', '10' 
Insert into Base31 SELECT 'C', '11' 
Insert into Base31 SELECT 'D', '12' 
Insert into Base31 SELECT 'F', '13' 
Insert into Base31 SELECT 'G', '14' 
Insert into Base31 SELECT 'H', '15' 
Insert into Base31 SELECT 'J', '16' 
Insert into Base31 SELECT 'K', '17' 
Insert into Base31 SELECT 'L', '18' 
Insert into Base31 SELECT 'M', '19' 
Insert into Base31 SELECT 'N', '20' 
Insert into Base31 SELECT 'P', '21' 
Insert into Base31 SELECT 'Q', '22' 
Insert into Base31 SELECT 'R', '23' 
Insert into Base31 SELECT 'S', '24' 
Insert into Base31 SELECT 'T', '25' 
Insert into Base31 SELECT 'V', '26' 
Insert into Base31 SELECT 'W', '27' 
Insert into Base31 SELECT 'X', '28' 
Insert into Base31 SELECT 'Y', '29' 
Insert into Base31 SELECT 'Z', '30' 

我想將這些主鍵轉換爲數字值,但我一直運行int int限制。我已經改變了所有使用大的int數據類型。我怎樣才能讓算法使用大的int數據類型?

GO 
CREATE Proc Base_31 @v varchar(8) 

as  

DECLARE @Ai bigint 
DECLARE @Bi bigint 
DECLARE @Ci bigint 
DECLARE @Di bigint 
DECLARE @Ei bigint 
DECLARE @Fi bigint 
DECLARE @Gi bigint 
DECLARE @Hi bigint 

SELECT @Ai = NumberValue     from Base31 where  RIGHT(@v,1) = ID 
SELECT @Bi = (NumberValue * POWER(31,1)) from Base31 where LEFT(RIGHT(@v,2),1) = ID 
SELECT @Ci = (NumberValue * POWER(31,2)) from Base31 where LEFT(RIGHT(@v,3),1) = ID 
SELECT @Di = (NumberValue * POWER(31,3)) from Base31 where LEFT(RIGHT(@v,4),1) = ID 
SELECT @Ei = (NumberValue * POWER(31,4)) from Base31 where LEFT(RIGHT(@v,5),1) = ID 
SELECT @Fi = (NumberValue * POWER(31,5)) from Base31 where LEFT(RIGHT(@v,6),1) = ID 
SELECT @Gi = (NumberValue * POWER(31,6)) from Base31 where LEFT(RIGHT(@v,7),1) = ID 
SELECT @Hi = (NumberValue * POWER(31,7)) from Base31 where LEFT(  @v ,1) = ID 

SELECT @v  AS Original 
    , Cast(@Ai AS bigint) 
    + Cast(@Bi AS bigint) 
    + Cast(@Ci AS bigint) 
    + Cast(@Di AS bigint) 
    + Cast(@Ei AS bigint) 
    + Cast(@Fi AS bigint) 
    + Cast(@Gi AS bigint) 
    + Cast(@Hi AS bigint) 
    as [Base 31 converted] 
GO 
+0

但是這個PK定義沒有語義,它只是一個句柄。它可以被任何任意的句柄取代,例如單調遞增的int。 – 2013-03-07 18:11:35

回答

2

問題是POWER函數返回與第一個參數相同的類型。所以你只需要明確地將第一個參數投給bigint。

該語句將失敗:

select power(31,7) 

而這其中的工作原理:

select power(cast(31 as bigint),7) 
2

有一個更好的方式來做到這一點。下面的方法適用於任意長度的數字和任意的基數,只需稍作調整:

-- First convert a bigint to base-31 number string. 
DECLARE @number bigint 

SET @number = 123740194325432 

DECLARE @Base31 table 
(Digit varchar(1) NOT NULL, 
Value bigint NOT NULL PRIMARY KEY) 

INSERT into @Base31 (Digit, Value) VALUES ('0', '0') 
INSERT into @Base31 (Digit, Value) VALUES ('1', '1') 
INSERT into @Base31 (Digit, Value) VALUES ('2', '2') 
INSERT into @Base31 (Digit, Value) VALUES ('3', '3') 
INSERT into @Base31 (Digit, Value) VALUES ('4', '4') 
INSERT into @Base31 (Digit, Value) VALUES ('5', '5') 
INSERT into @Base31 (Digit, Value) VALUES ('6', '6') 
INSERT into @Base31 (Digit, Value) VALUES ('7', '7') 
INSERT into @Base31 (Digit, Value) VALUES ('8', '8') 
INSERT into @Base31 (Digit, Value) VALUES ('9', '9') 
INSERT into @Base31 (Digit, Value) VALUES ('B', '10') 
INSERT into @Base31 (Digit, Value) VALUES ('C', '11') 
INSERT into @Base31 (Digit, Value) VALUES ('D', '12') 
INSERT into @Base31 (Digit, Value) VALUES ('F', '13') 
INSERT into @Base31 (Digit, Value) VALUES ('G', '14') 
INSERT into @Base31 (Digit, Value) VALUES ('H', '15') 
INSERT into @Base31 (Digit, Value) VALUES ('J', '16') 
INSERT into @Base31 (Digit, Value) VALUES ('K', '17') 
INSERT into @Base31 (Digit, Value) VALUES ('L', '18') 
INSERT into @Base31 (Digit, Value) VALUES ('M', '19') 
INSERT into @Base31 (Digit, Value) VALUES ('N', '20') 
INSERT into @Base31 (Digit, Value) VALUES ('P', '21') 
INSERT into @Base31 (Digit, Value) VALUES ('Q', '22') 
INSERT into @Base31 (Digit, Value) VALUES ('R', '23') 
INSERT into @Base31 (Digit, Value) VALUES ('S', '24') 
INSERT into @Base31 (Digit, Value) VALUES ('T', '25') 
INSERT into @Base31 (Digit, Value) VALUES ('V', '26') 
INSERT into @Base31 (Digit, Value) VALUES ('W', '27') 
INSERT into @Base31 (Digit, Value) VALUES ('X', '28') 
INSERT into @Base31 (Digit, Value) VALUES ('Y', '29') 
INSERT into @Base31 (Digit, Value) VALUES ('Z', '30') 

DECLARE @base bigint 
DECLARE @power bigint 
DECLARE @divisor bigint 
DECLARE @output varchar(50) 
DECLARE @digit varchar(1) 
DECLARE @digitValue bigint 

SET @output = '' 
SET @base = 31 

IF @number < 0 
BEGIN 
    SET @number = ABS(@number) 
    SET @output = '-' 
END 

IF NOT @number = 0 
BEGIN 
    /* Due to the fact that the LOG10 function in SQL yields a float which limits the 
    available precision of the logarithm, numbers above 147209586032873 may have some 
    artifacts, i.e. LOG10(147209586032874) = LOG10(147209586032873). In actual practice, 
    I've found that numbers above 31^10 - 5 may manifest a leading zero when they are 
    near a power of 31, i.e. numbers in the ranges 31^10 - 4 to 31^10 - 1 and 
    31^11 - 158 to 31^11 - 1. */ 

    SET @power = FLOOR(LOG10(@number)/LOG10(@base)) 
END 

WHILE @power >= 0 AND @number > 0 
BEGIN 
    SET @divisor = POWER(@base, @power) 
    SET @digitValue = @number/@divisor 
    SET @number = @number % @divisor 

    SELECT @digit = Digit 
    FROM @Base31 
    WHERE Value = @digitValue 

    SELECT @output = @output + @digit 
    SET @power = @power - 1 
END 

SET @output = @output + COALESCE(REPLICATE('0', @power + 1), '0') 

SELECT @output 

-- Now convert the base-31 number string back to a bigint and see if we're right. 
DECLARE @position bigint 

SET @position = LEN(@output) 
SET @number = 0 

WHILE @position > 0 
BEGIN 
    SET @digit = SUBSTRING(@output, @position, 1) 

    SELECT @digitValue = Value 
    FROM @base31 
    WHERE Digit = @digit 

    SET @power = LEN(@output) - @position 
    SET @number = @number + (@digitValue * POWER(@base, @power)) 
    SET @position = @position - 1 
END 

SELECT @number