长到基数X字母数字代码问题

时间:2015-07-16 07:38:45

标签: c# sql

我有以下SQL函数 - 它在表Insert上被称为触发器。我需要将ID转换为仅包含特定字符的字母数字ID:

USE [NewCo]
GO
/****** Object:  UserDefinedFunction [dbo].[fnBase10ToBase32]    Script Date: 16/07/2015 06:51:36 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER function [dbo].[fnBase10ToBase32]
(
@val as BigInt
)
returns varchar(7)
as
Begin

--TAKEN FROM http://geekswithblogs.net/bbiales/archive/2009/05/04/131732.aspx 2013-12-01

--Overflow at @val > 9,223,372,035,775,033,983
  --bigint MAX = 9,223,372,036,854,775,807
  --offset = 1,079,741,824
  --Biggest 7Char @val = 33,279,996,543(ZZZZZZZ)

  DECLARE @Base int = 32
  DECLARE @OffSet int = 1079741824
  /*
   (minimum for 7 chars = 1073741824)
    but - 1073741824 means @val of 1 = 2000002 - TOO many 0's so increase offset
  */


  SET @val += @OffSet

  /* Check if value is valid and if we get a valid base (2 through 36) */
  If (@val<0) return Null;

  /* variable to hold final answer */
  Declare @answer as varchar(7);

  /* Following variable contains all 
     possible alpha numeric letters for any valid base 
  */

  Declare @alldigits as varchar(32);
  Set @alldigits='023456789ABCDEFGHJKLMNPRSTUVWXYZ'

  /* Set the initial value of 
     final answer as empty string 
  */
  Set @answer='';

  /* Loop while the source value remains greater than 0 */
  While @val>0
  Begin
    Set @answer=Substring(@alldigits,@val % @Base + 1,1) + @answer;
    Set @val = @val / @Base;
  End

  /* Return the final answer */
  return REVERSE(@answer);

End

注意:上述工作正常(或似乎无论如何)。

我现在需要将此功能移至C#。我写了下面的内容,但它没有给出与SQL函数相同的结果,并且当(val%baseNo = 31)时会导致outOfRange异常。我试图将baseNo设置为31以避免outOfRange异常,但结果仍然不一样:

int baseNo = 32-1;
int offset = 1079741824;

long val = ProdID + offset;

if (val < 0)
{
    return null;
}

/* variable to hold final answer */
string reg = string.Empty;

//char[] alldigits = new char[] { '0', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
string alldigitsString = "023456789ABCDEFGHJKLMNPRSTUVWXYZ";

/* Loop while the source value remains greater than 0 */
while (val > 0)
{

    reg = alldigitsString.Substring((int)(val % baseNo) + 1, 1) + reg;
    val = val / (baseNo + 1);
}

/* Return the final answer */
char[] arr = reg.ToCharArray();
Array.Reverse(arr);
return new string(arr);

以下是不同功能的结果:

ID      SQL         C#
57596   "WLVS602"   "DGVZ833"
57597   "XLVS602"   "EGVZ833"
57598   "YLVS602"   "FGVZ833"
57599   "ZLVS602"   "GGVZ833"
57600   "0MVS602"   "HHVZ833"

如您所见,模式相同,但数字不同

任何人都可以看到我的结果不同的地方/原因吗?我想坚持SQL函数结果,但在C#代码中。

我没有尝试,但我想我可以改变偏移量以使结果相同 - 但为什么它会有所不同?

1 个答案:

答案 0 :(得分:3)

数组和字符串索引在C#中从零开始。

const int baseNo = 32;
const int offset = 1079741824;
const string allDigits = "023456789ABCDEFGHJKLMNPRSTUVWXYZ";

if (val < 0) return null;

long val = ProdID + offset;

var data = new char[255];
var index = 0;

while (val > 0)
{
    data[index++] = allDigits[(int)(val % baseNo)];
    val /= baseNo;
}

return new string(data, 0, index);

我还冒昧地避免了一些常见的性能陷阱,并清理了代码(摆脱了一些基于SQL的限制)。它现在看起来更像C#:)

您可以使用数据库中ID字段的最大大小来创建char[]我创建的大小 - 或者如果您想更精确,(int)Math.Ceiling(Math.Log(val, baseNo)) + 1将适用于几乎可以为你提供所需数量的字符。