Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Инкремент строкового номера документа  [new]
Antei
Member

Откуда: Ukraine
Сообщений: 121
В документе имеется строковое поле Number. Оно содержит некий номер состоящий из символов верхнего регистра A-Z. Стоит задача автоинкрементации этого номера, например:

A->B
B->C
...
Z->AA
AA->AB
...
AZ->BA

и т.д.

Посоветуйте плз, где можно поискать что-нибудь готовое по этому поводу?
11 дек 08, 17:59    [6558732]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Заятс
Member

Откуда: Киев
Сообщений: 316
SELECT chr(ASCII('A')+1) FROM dual
Результат запроса - 'B'
11 дек 08, 18:15    [6558865]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Antei
Member

Откуда: Ukraine
Сообщений: 121
Заятс
SELECT chr(ASCII('A')+1) FROM dual
Результат запроса - 'B'


Да я понимаю. :-) Но ведь наверняка этот вопрос - баян, а писать самому - велосипед. Есть ли что-нибудь готовое? Если кто знает, поделитесь плз. :-)
11 дек 08, 18:30    [6558971]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
expla
Guest
Заятс
SELECT chr(ASCII('A')+1) FROM dual
Результат запроса - 'B'


Наивный. От кодировки БД зависит.
11 дек 08, 18:34    [6558991]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Antei
Member

Откуда: Ukraine
Сообщений: 121
expla
Наивный. От кодировки БД зависит.

Нужно решение только для символов ASCII
11 дек 08, 18:37    [6558999]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
expla
Заятс
SELECT chr(ASCII('A')+1) FROM dual
Результат запроса - 'B'


Наивный. От кодировки БД зависит.

The english alphabet does not.
11 дек 08, 18:38    [6559003]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Wadim S
Member

Откуда: Ukraine
Сообщений: 178
expla

Наивный. От кодировки БД зависит.

А что, неужели есть кодировки где латиница непоследовательно идет?
11 дек 08, 18:44    [6559021]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
Antei
expla
Наивный. От кодировки БД зависит.

Нужно решение только для символов ASCII

Если не требуется обязательной последовательности а требуются только уникальные строковые идентификаторы, то, быть может, utl_encode можно приспособить?

В противном случае - перевод числа в систему счисления с основанием 26 (тут ведь нет вопросов?) + смещение каждого знака на ascii('A')
11 дек 08, 19:02    [6559078]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
expla
Guest
Wadim S, andrey_anonymous,

set pagesize 19
select
    substr(utl_raw.cast_to_raw(convert(chr(level), 'UTFE')), 1, 8),
    chr(level),
    substr(ascii(convert(chr(level), 'UTFE')), 1, 8),
    level
from dual
connect by level <= 127;



...
SUBSTR(U C SUBSTR(A LEVEL
-------- - -------- ----------
81 a 129 97
82 b 130 98
83 c 131 99
84 d 132 100
85 e 133 101
86 f 134 102
87 g 135 103
88 h 136 104
89 i 137 105
91 j 145 106

92 k 146 107
93 l 147 108
94 m 148 109
95 n 149 110
96 o 150 111
97 p 151 112

SUBSTR(U C SUBSTR(A LEVEL
-------- - -------- ----------
98 q 152 113
99 r 153 114
A2 s 162 115

A3 t 163 116
A4 u 164 117
A5 v 165 118
A6 w 166 119
A7 x 167 120
A8 y 168 121
A9 z 169 122
...

Функция ASCII врёт, потому как UTFE для неё на моей БД не родная. Для прописных букв картина сходная.
11 дек 08, 19:08    [6559090]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
expla
Guest
Интересный момент всплыл. Ведущие A - имеют значение, т.е. 'A' != 'AA'? Если имею, то нужно немного переделать функцию.

set serveroutput on
declare
function str_inc(
  s in varchar2
) return varchar2
is
  p number;
  n number;
  res varchar2(32756 BYTE);
  alpha constant varchar2(26 CHAR) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
begin
    if s is null then
        return null;
    end if;
    p := length(s);
    loop
        if p=0 then -- Переполнение
            res := 'B'||res; -- Тут можно вместо B - A прописать. Если считать, что ведущие A, в отличии от ведущих 0, имеют значение.
            exit;
        end if;
        n := instr(alpha, substr(s, p, 1));
        if n between 1 and 25  then -- Переноса нет
            res :=  substr(s, 1, p - 1)||substr(alpha, n + 1, 1)||res;
            exit;
        elsif n = 26 then -- Перенос в следующий разряд
            res :=  'A'||res;
            p := p-1;
        else
            raise_application_error(-20100, 'Invalid number');
        end if;
    end loop;
    return res;
end;
begin
    dbms_output.put_line('NULL '||str_inc(null));
    dbms_output.put_line('A '||str_inc('A'));
    dbms_output.put_line('B '||str_inc('B'));
    dbms_output.put_line('Z '||str_inc('Z'));
    dbms_output.put_line('CDZ '||str_inc('CDZ'));
    dbms_output.put_line('CZD '||str_inc('CZD'));
    dbms_output.put_line('CZZZ '||str_inc('CZZZ'));
    dbms_output.put_line('ZZZZ '||str_inc('ZZZZ'));
end;
/

NULL
A B
B C
Z BA
CDZ CEA
CZD CZE
CZZZ DAAA
ZZZZ BAAAA

PL/SQL procedure successfully completed.
11 дек 08, 19:51    [6559190]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Elic
Member

Откуда:
Сообщений: 29979
STFF задачка для желающих размяться (~пятничная)Кажется - совсем просто ;)
11 дек 08, 19:53    [6559192]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
expla

Функция ASCII врёт

Да нет, не врет - все правильно она показывает.
Я про EBDIC-то и забыл... Извращенцы из IBM, его выдумавшие, развлеклись знатно - хорошо хоть алфавитный порядок не перепутали, хотя и напихали себе по одному "левому" символу как в строчные, так и в прописные (0xE1, 0xA1) :)
Тут ключевой момент - это Binary coded Decimal Interchange Format

Если что - вот правила преобразования UNICODE в UTF-EBDIC, "пропуски" и прочая путаница в кодах определяются табличками 2 и 3.
11 дек 08, 20:04    [6559226]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Antei
Member

Откуда: Ukraine
Сообщений: 121
andrey_anonymous
Если не требуется обязательной последовательности а требуются только уникальные строковые идентификаторы, то, быть может, utl_encode можно приспособить?

В противном случае - перевод числа в систему счисления с основанием 26 (тут ведь нет вопросов?) + смещение каждого знака на ascii('A')


Да, нужна последовательность.

>перевод числа в систему счисления с основанием 26 (тут ведь нет вопросов?)
:-) Вопрос есть - что ты здесь имеешь ввиду? Руками делить разряды на 26, вычислять остаток и пр и пр?
11 дек 08, 20:14    [6559254]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Antei
Member

Откуда: Ukraine
Сообщений: 121
expla,

Сенкс, буду разбираться :-)
11 дек 08, 20:15    [6559257]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
Antei

:-) Вопрос есть - что ты здесь имеешь ввиду? Руками делить разряды на 26, вычислять остаток и пр и пр?

Разряды-то зачем?
Стандартный способ - остатками от целочисленного деления числа на основание системы определяются цифры, частное идет в следующую итерацию.

См. ссылки от Elic, оказывается, народ недавно именно в эту игрушку развлекался :)
11 дек 08, 20:23    [6559270]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Elic
Member

Откуда:
Сообщений: 29979
Antei
>перевод числа в систему счисления с основанием 26 (тут ведь нет вопросов?)
:-) Вопрос есть - что ты здесь имеешь ввиду? Руками делить разряды на 26, вычислять остаток и пр и пр?
Я здесь не вижу 26-ричной системы счисления:
Z->AA  =>  Z = A*26 + A  =>  Z = 27 * A  =>  брррр.... :)

26-ричная система счисления - это когда A симвализирует ноль (и т.д до Z=25) и, соответственно, Z->BA
11 дек 08, 20:24    [6559275]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
expla
нужно немного переделать функцию.

А что так сложно-то?
declare
function str_inc(
  s in varchar2
) return varchar2
is
  p number;
  n number := 0;
  res varchar2(32756 BYTE);
  alpha constant varchar2(26 CHAR) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
begin
    if s is null then
        return null;
    end if;
    p := length(s);
 
    for i in 1..p loop
      n:=n*26+instr(alpha, substr(s, i, 1))-1;
    end loop;
    n:= n+1;
    while n>0 loop
      res := substr(alpha,mod(n,26)+1,1)||res;
      n := trunc(n/26);
    end loop;
 
    return res;
end;
begin
    dbms_output.put_line('NULL '||str_inc(null));
    dbms_output.put_line('A '||str_inc('A'));
    dbms_output.put_line('B '||str_inc('B'));
    dbms_output.put_line('Z '||str_inc('Z'));
    dbms_output.put_line('CDZ '||str_inc('CDZ'));
    dbms_output.put_line('CZD '||str_inc('CZD'));
    dbms_output.put_line('CZZZ '||str_inc('CZZZ'));
    dbms_output.put_line('ZZZZ '||str_inc('ZZZZ'));
end;
/
 
NULL 
A B
B C
Z BA
CDZ CEA
CZD CZE
CZZZ DAAA
ZZZZ BAAAA
 
PL/SQL procedure successfully completed
 
SQL> 
11 дек 08, 20:40    [6559297]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
andrey_anonymous
А что так сложно-то?

С учетом замечания Elic:
set serveroutput on
declare
function str_inc(
  s in varchar2
) return varchar2
is
  p number;
  n number := 0;
  res varchar2(32756 BYTE);
  alpha constant varchar2(26 CHAR) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
begin
    if s is null then
        return null;
    end if;
 
    p := length(s);
 
    for i in 1..p loop
      n:=n*26+instr(alpha, substr(s, i, 1))-1;
    end loop;
    n:= n+1;
    while n>0 loop
      res := substr(alpha,mod(n,26)+1,1)||res;
      n := trunc(n/26);
    end loop;
 
    if length(res) > length(s) then
      res := 'A'||substr(res, 2);
    end if;
    return res;
end;
begin
    dbms_output.put_line('NULL '||str_inc(null));
    dbms_output.put_line('A '||str_inc('A'));
    dbms_output.put_line('B '||str_inc('B'));
    dbms_output.put_line('Z '||str_inc('Z'));
    dbms_output.put_line('CDZ '||str_inc('CDZ'));
    dbms_output.put_line('CZD '||str_inc('CZD'));
    dbms_output.put_line('CZZZ '||str_inc('CZZZ'));
    dbms_output.put_line('ZZZZ '||str_inc('ZZZZ'));
end;
/
 
NULL 
A B
B C
Z AA
CDZ CEA
CZD CZE
CZZZ DAAA
ZZZZ AAAAA
 
PL/SQL procedure successfully completed
 
SQL> 
11 дек 08, 20:56    [6559349]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
VBR
Member

Откуда:
Сообщений: 79
Еще вариант. Я исходил из того (может и ошибочно), что для генерации
уникальных идентификаторов будет использоваться nextval (sequence),
чтобы при многопользовательской работе проблем не было.
Т.е. number надо в этот формат преобразовать.

create or replace function ttt (p_val number) return varchar2 is
	buf varchar2(200);  
  alf  varchar2(26) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  val number;
begin
buf:='';
val:=p_val;
loop
   if(mod(val,26))=0 then
     buf:= substr(alf,(mod(val,26)),1)||buf;
   else                                       
     buf:= substr(alf,(mod(val,26)+1),1)||buf;
  end if;	 
   val:=trunc(val/26);
   if(val=0) then
     exit;
   end if;	
end loop;
return(buf);
end ttt;

Для проверки
select (level-1),ttt(level-1) from dual connect by level<1000
11 дек 08, 22:06    [6559537]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
VBR
Member

Откуда:
Сообщений: 79
Да...
Посмотрел код andrey_anonymous. Вообщем, зря старался.
Но ничего, потренировался :)
11 дек 08, 22:16    [6559574]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
expla
Guest
andrey_anonymous
А что так сложно-то?


Может теперь производительностью померяемся.

В 25/26 мой метод инкрементирует лишь один младший разряд и сразу возвращает результат. Т.е. имеем экономию на прямом и обратном преобразовании системы счисления всего числа в пользу преобразования только одного разряда в большинстве случаев.

Но раз автору это уже не нужно, то и фиг с ним...
11 дек 08, 23:59    [6560046]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18351
expla
В 25/26 мой метод инкрементирует лишь один младший разряд и сразу возвращает результат. Т.е. имеем экономию на прямом и обратном преобразовании системы счисления всего числа в пользу преобразования только одного разряда в большинстве случаев.

То же самое тривиально делается и для моей интерпретации Вашего кода. Более того, если все-таки не брать в расчет EBDIC, то его можно еще "ускорить" на длинных числах за счет более эффективного преобразования 4-байтых последовательностей.
В общем, тут поле непаханное.

Мне было важнее показать преобразование чисел из одной системы счисления в другую, а потом показать Elic что это можно применить к данной задаче даже с учетом правила Z++=>AA.

...но суть не в том - я просто вспомнил, как когда-то пытался помочь одной девушке отладить ассемблерную программку-калькулятор. Она пошла ровно по тому же пути - написала всю арифметику "в символах", руками... Сотни и сотни строк кода...
И очень удивилась, когда узнала, что строку можно тривиально конвертнуть в число, воспользоваться сумматором процессора и получить решение на полтора экрана... воооот ;)
12 дек 08, 01:51    [6560266]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 10045
Depending on what you do with document number it might be more efficient to store document number as plain decimal number and convert it в систему счисления с основанием 26 for display only. Especially if there is a need to select a range of document numbers:

WHERE doc_number BETWEEN From_Base26('ZA') AND From_Base26('AAA')

Try something like this with "строковое поле Number".

SY.

Сообщение было отредактировано: 12 дек 08, 04:13
12 дек 08, 04:10    [6560333]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
Elic
Member

Откуда:
Сообщений: 29979
andrey_anonymous
показать Elic что это можно применить к данной задаче даже с учетом правила Z++=>AA.
    if length(res) > length(s) then
      res := 'A'||substr(res, 2);
    end if;
Вот именно, что это годится лишь для операции ++, но не для какой ещё арифметики :)
12 дек 08, 09:39    [6560697]     Ответить | Цитировать Сообщить модератору
 Re: Инкремент строкового номера документа  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
SY
Depending on what you do with document number it might be more efficient to store document number as plain decimal number and convert it в систему счисления с основанием 26 for display only. Especially if there is a need to select a range of document numbers:

WHERE doc_number BETWEEN From_Base26('ZA') AND From_Base26('AAA')

Try something like this with "строковое поле Number".

SY.

Во, во..
12 дек 08, 09:57    [6560789]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Oracle Ответить