我有以下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#代码中。
我没有尝试,但我想我可以改变偏移量以使结果相同 - 但为什么它会有所不同?
答案 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
将适用于几乎可以为你提供所需数量的字符。