Сделанный на заказ SQL Server «кодировка» sproc - есть ли более аккуратный способ сделать это? - PullRequest
1 голос
/ 11 сентября 2008

Мне просто интересно, есть ли лучший способ сделать это в SQL Server 2005.

По сути, я беру originator_id (число от 0 до 99) и «next_element» (на самом деле это просто последовательный счетчик от 1 до 999 999). Мы пытаемся создать из них 6-значный код.

Originator_id умножается на миллион, а затем добавляется счетчик, давая нам число от 0 до 99 999 999.

Затем мы конвертируем это в строку «base 32» - фальшивую базу 32, где мы на самом деле просто используем 0-9 и AZ, но с некоторыми из более запутанных алфавитов, удаленных для ясности (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;

Я не отчаянно беспокоюсь об оптимизации, если этот метод на самом деле не на порядок (или около того) хуже, чем любая другая альтернатива.

Код выполняется только небольшими пакетами, возможно, генерируя 20 или 30 кодов каждые 10 минут или около того. Из-за большого диапазона чисел я не хочу предварительно вычислять коды в огромной таблице (в любой конкретной установке будут использоваться только небольшие карманы всего диапазона кодов).

Тем не менее, я уверен, что, возможно, есть более аккуратный способ достижения того же результата - особенно те деления и вычитания.

Любая конструктивная критика, замечания или предложения приветствуются.

Ответы [ 2 ]

3 голосов
/ 11 сентября 2008

Видя, что это SQL Server 2005, есть ли причина не использовать хранимую процедуру CLR? Тогда вы можете использовать предпочитаемый вами язык CLR, и это будет относительно прямой порт существующего кода Delphi.

0 голосов
/ 11 сентября 2008

Хотя это явно можно сделать в SQL Server 2005, я думаю, что он достаточно «не-базы данных», чтобы иметь смысл какую-то предварительно скомпилированную языковую подпрограмму высокого уровня.

Я написал DLL для Interbase / Firebird и T-SQL sprocs для SQL Server, но никогда не выполнял процедуру CLR. Это будет интересное упражнение!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...