定制的SQL Server"编码"存储过程-是否有更整洁的方式做到这一点?

时间:2020-03-05 18:51:05  来源:igfitidea点击:

我只是想知道在SQL Server 2005中是否有更好的方法可以做到这一点。

实际上,我正在使用一个originator_id(一个介于0和99之间的数字)和一个" next_element"(实际上只是一个介于1和999,999之间的顺序计数器)。
我们正在尝试从中创建一个6个字符的"代码"。

将originator_id乘以一百万,然后将计数器相加,得到一个介于0到99,999,999之间的数字。

然后,我们将其转换为假基数32的"基数32"字符串,实际上我们只使用0-9和A-Z,但为清晰起见,删除了一些更混乱的字母数字(I,O,S,Z)。

为此,我们只需要在每个阶段将数字除以32的幂即可,将获得的每个幂的结果用作所选字符数组中某个字符的索引。

Thus, an originator ID of 61 and NextCodeElement of 9 gives a code of '1T5JA9'

(61 * 1,000,000) + 9 = 61,000,009
61,000,009 div (5^32 = 33,554,432) =  1 = '1'
27,445,577 div (4^32 =  1,048,576) = 26 = 'T'
   182,601 div (3^32 =     32,768) =  5 = '5'
    18,761 div (2^32 =      1,024) = 18 = 'J'
       329 div (1^32 =         32) = 10 = 'A'
         9 div (0^32 =          1) =  9 = '9'

so my code is 1T5JA9

以前我曾经在Delphi中使用过这种算法,但是现在我确实需要能够在SQL Server 2005中重新创建它。显然,我手头的功能与Delphi中的功能不一样,但这就是我照例行事。它可以正常工作,并且我可以生成代码(或者将代码重构回其组件)。

但是它看起来有点漫长,而且我不确定选择将结果除以int的技巧(即,确实将其强制转换)一定是"正确的",是否有一种更好的SQLS方式可以处理这种情况事物?

CREATE procedure dummy_RP_CREATE_CODE @NextCodeElement int, @OriginatorID int,
  @code varchar(6) output
as
begin
  declare @raw_num int;
  declare @bcelems char(32);
  declare @chr int;

  select @bcelems='0123456789ABCDEFGHJKLMNPQRTUVWXY';
  select @code='';

  -- add in the originator_id, scaled into place
  select @raw_num = (@OriginatorID * 1000000) + @NextCodeElement;

  -- now to convert this to a 6-char code

  -- 5^32
  select @chr = @raw_num / 33554432;
  select @raw_num = @raw_num - (@chr * 33554432);
  select @code = @code + SUBSTRING(@bcelems, 1 + @chr, 1);

  -- 4^32
  select @chr = @raw_num / 1048576;
  select @raw_num = @raw_num - (@chr * 1048576);
  select @code = @code + SUBSTRING(@bcelems, 1 + @chr, 1);

  -- 3^32
  select @chr = @raw_num / 32768;
  select @raw_num = @raw_num - (@chr * 32768);
  select @code = @code + SUBSTRING(@bcelems, 1 + @chr, 1);

  -- 2^32
  select @chr = @raw_num / 1024;
  select @raw_num = @raw_num - (@chr * 1024);
  select @code = @code + SUBSTRING(@bcelems, 1 + @chr, 1);

  -- 1^32
  select @chr = @raw_num / 32;
  select @raw_num = @raw_num - (@chr * 32);
  select @code = @code + SUBSTRING(@bcelems, 1 + @chr, 1);

  -- 0^32  
  select @code = @code + SUBSTRING(@bcelems, 1 + @raw_num, 1);

  -- that's it!
end;

除非此方法实际上比其他方法差一个数量级(或者大约一个数量级),否则我并不急于优化。

该代码只会被执行一小段,可能每10分钟左右生成20或者30个代码。由于数字范围很大,因此我不想将代码预先计算到一个巨大的表中(在任何给定的安装中都只会使用整个代码范围的一小部分)。

但是,我敢肯定,有一种更整齐的方法可以达到相同的结果,尤其是那些除法和减法。

任何建设性的批评,意见或者建议都将受到欢迎。

解决方案

回答

看到它是SQL Server 2005,是否有理由不使用CLR存储过程?然后,我们可以使用选择的CLR语言,并且它可能是现有Delphi代码的相对直接端口。

回答

尽管可以在SQL Server 2005中很明显地做到这一点,但我认为它具有足够的"非数据库性",某种预编译的高级语言例程才有意义。

我已经为Interbase / Firebird编写了DLL,为SQL Server编写了T-SQL sproc,但从未编写CLR例程。这将是一个有趣的练习!