Инструменты пользователя

Инструменты сайта


Боковая панель

Введение

Статьи и часто задаваемые вопросы

Установка и настройка

Обработка ошибок

Полезные запросы SQL

Тематические группы

sql003.summa_propisju



SQL003. Сумма прописью

Версии сервера

0.9 1.0 1.5.3 1.5.4 1.5.5 2.0 2.0.3 2.0.4 2.1 2.5 3.0
- - - - - - - - Да Да Да

Описание

Данная хранимая процедура преобразует переданное ей в качестве параметра значение суммы в текстовое представление.

Ограничения:

  1. В области строковых констант хранимая процедура может быть изменена под любой язык, но корректно алгоритм будет работать только на восточно-славянской группе языков (русский, белорусский, украинский), имеющих одинаковые правила склонения числительных.
  2. Данная хранимая процедура будет корректно работать только на «двухуровневых» валютах (доллар-цент, рубль-копейка, грывня-копийка) с отношением 1/100 старшего уровня к младшему (на момент написания данной статьи это практически все валюты мира). Данная хранимая процедура не может использоваться в многоуровневых валютах (например, валюта Соединеннго Королевства до реформы 1972г., имевшая в составе несколько уровней: фунт-шиллинг(стерлинг)-пенс) и валютах, имеющих отношение верхнего уровня к нижнему, отличное от 1/100 (например, валюта Соединеннго Королевства до реформы 1972г., где: 1 фунт = 12 шиллингов(стерлингов)).

Пример

SET TERM ^ ;
 
CREATE OR ALTER PROCEDURE CURRENCYSTR (
    VAL NUMERIC(15,2),
    LANG VARCHAR(2),
    SHOWCURRENCY INTEGER)
RETURNS (
    CURR_STR VARCHAR(1000))
AS
DECLARE variable RAZRYAD VARCHAR(50);
DECLARE variable RAZRYAD_IDX VARCHAR(28);
DECLARE variable HUNDREDS VARCHAR(64);
DECLARE variable HUNDREDS_IDX VARCHAR(30);
DECLARE variable TENS VARCHAR(69);
DECLARE variable TENS_IDX VARCHAR(40);
DECLARE variable ONES VARCHAR(139);
DECLARE variable ONES_IDX VARCHAR(100);
DECLARE variable SIGN_OF_VAL VARCHAR(6);
DECLARE variable RAZ INTEGER;
DECLARE variable CENTS VARCHAR(3);
DECLARE variable VAL_STR VARCHAR(20);
DECLARE variable NUM VARCHAR(20);
DECLARE variable I INTEGER;
DECLARE variable BUF VARCHAR(200);
DECLARE variable BUF1 VARCHAR(200);
DECLARE variable CURR_ABR VARCHAR(5);
DECLARE variable MINUS_STR VARCHAR(10);
BEGIN
  lang = UPPER(lang);
  /* Константы */
  IF (lang IS NULL) THEN lang = 'UA';
  IF (:lang = 'UA') THEN
  BEGIN
    curr_abr = 'грн.';
    minus_str = 'мінус';
    razryad_idx = /* 2.2 */ '0100010506071307200828113911';
    razryad = 'тисячмільйонмільярдтрильйонквадрильйонквінтильйон';
    hundreds_idx = /* 2.1 */ '010013046106169257318396458539';
    hundreds = 'стодвістітристачотиристап''ятсотшістсотсімсотвісімсотдев''ятсот';
    tens_idx = /* 2.2 */ '0100010001080908170522093109400848105810';
    tens = 'двадцятьтридцятьсорокп''ятдесятшістдесятсімдесятвісімдесятдев''яносто';
    ones_idx = /* 3.2 */ '0010000100001000010300406010050150502003023050280703506041100511006110071120831109411105101151212713';
    ones = 'тричотирип''ятьшістьсімвісімдев''ятьдесятьодинадцятьдванадцятьтринадцятьчотирнадцятьп''ятнадцятьшістнадцятьсімнадцятьвісімнадцятьдев''ятнадцять';
  END
  ELSE IF ((:lang = 'RU')) THEN
  BEGIN
    curr_abr = 'руб.';
    minus_str = 'минус';
    razryad_idx = /* 2.2 */ '0100010506071308210829114011';
    razryad = 'тисячміллионмиллиардтриллионквадриллионквинтиллион';
    hundreds_idx = /* 2.1 */ '010013046106169257328407479569';
    hundreds = 'стодвеститристачетырестапятьсотшестьсотсемьсотвосемьсотдевятьсот';
    tens_idx = /* 2.2 */ '0100010001080908170522093110410950116109';
    tens = 'двадцатьтридцатьсорокпятьдесятшестьдесятсемьдесятвосемьдесятдевяносто';
    ones_idx = /* 3.2 */ '0010000100001000010300406010040140501904023060290603506041110521006210072120841009411105101151212712';
    ones = 'тричетырепятьшестьсемьвосемьдевятьдесятьодиннадцатьдвенадцатьтринадцатьчетырнадцатьпятнадцатьшестнадцатьсемнадцатьвосемнадцатьдевятнадцать';
  END
 
  IF (showcurrency IS NULL) THEN showcurrency = 0;
  curr_str = '';
 
  /* Смотрим знак */
  IF (val < 0) THEN BEGIN
    sign_of_val = minus_str||' ';
    val = -val;
  END ELSE
    sign_of_val = '';
 
  /* Выбираем и запоминаем копейки, убираем их из числа */
  val_str = CAST(val AS VARCHAR(20));
  i = POSITION('.' IN val_str);
  cents = lpad(SUBSTRING(val_str FROM i+1 FOR 2), 2, '0');
--  val_str = lpad(substring(val_str FROM 1 FOR i-1), ((i+1)/3*3), '0');
  val_str = lpad(SUBSTRING(val_str FROM 1 FOR i-1), (trunc((i+1)/3)*3), '0');
 
  /* Разбираем число */
  raz = 0; curr_str = '';
  while (val_str != '') do BEGIN
    /* Берём триаду символов */
    num = RIGHT(val_str, 3);
    /* Если не нулевое число */
    IF (num != '000') THEN BEGIN
      /* Берём сотни */
      i = CAST(SUBSTRING(num FROM 1 FOR 1) AS INT);
      buf = SUBSTRING(hundreds FROM CAST(SUBSTRING(hundreds_idx FROM i*3+1 FOR 2) AS INT)
        FOR CAST(SUBSTRING(hundreds_idx FROM i*3+3 FOR 1) AS INT));
 
      /* Далее десятки */
      /* Для "десятнадцатых" упрощённая обработка */
      IF (SUBSTRING(num FROM 2 FOR 1) = '1') THEN BEGIN
          /* Вставляем нужную "десятнадцать" */
          i = CAST(SUBSTRING(num FROM 2 FOR 2) AS INT);
          buf1 = SUBSTRING(ones FROM CAST(SUBSTRING(ones_idx FROM i*5+1 FOR 3) AS INT) FOR CAST(SUBSTRING(ones_idx FROM i*5+4 FOR 2) AS INT));
          IF (buf != '') THEN buf = buf || ' ';
          buf = buf || buf1;
      END ELSE
      /* Для "нормальных" чисел своя обработка */
      BEGIN
        /* Десятки */
        i = CAST(SUBSTRING(num FROM 2 FOR 1) AS INT);
        buf1 = SUBSTRING(tens FROM CAST(SUBSTRING(tens_idx FROM i*4+1 FOR 2) AS INT) FOR CAST(SUBSTRING(tens_idx FROM i*4+3 FOR 2) AS INT));
        IF (buf != '' AND buf1 != '') THEN buf = buf || ' ';
        buf = buf || buf1;
 
        /* Единицы */
        i = CAST(SUBSTRING(num FROM 3 FOR 1) AS INT);
        /* Смотрим количество для нужного окончания */
        IF (i = 1) THEN BEGIN
          IF (:lang = 'UA') THEN BEGIN
            IF (raz IN (0,1)) THEN buf1 = 'одна'; ELSE buf1 = 'один';
          END
          ELSE IF (:lang = 'RU') THEN BEGIN
            IF (raz = 1) THEN buf1 = 'одна'; ELSE buf1 = 'один';
          END
        END ELSE
        IF (i = 2) THEN BEGIN
          IF (:lang = 'UA') THEN BEGIN
            IF (raz IN (0,1)) THEN buf1 = 'дві'; ELSE buf1 = 'два';
          END
          ELSE IF (:lang = 'RU') THEN BEGIN
            IF (raz = 1) THEN buf1 = 'две'; ELSE buf1 = 'два';
          END
        END ELSE
          buf1 = SUBSTRING(ones FROM CAST(SUBSTRING(ones_idx FROM i*5+1 FOR 3) AS INT) FOR CAST(SUBSTRING(ones_idx FROM i*5+4 FOR 2) AS INT));
        IF (buf != '' AND buf1 != '') THEN buf = buf || ' ';
        buf = buf || buf1;
      END
 
      /* Разряд числа */
      buf1 = SUBSTRING(razryad FROM CAST(SUBSTRING(razryad_idx FROM raz*4+1 FOR 2) AS INT) FOR CAST(SUBSTRING(razryad_idx FROM raz*4+3 FOR 2) AS INT));
      IF (buf1 != '') THEN BEGIN
        /* Подбор окончания для разряда */
        IF (:lang = 'UA') THEN BEGIN
          IF (i = 1) THEN BEGIN
            IF (raz = 1) THEN buf1 = buf1 || 'а';
          END ELSE
          IF (i IN (2,3,4)) THEN BEGIN
            IF (raz = 1) THEN buf1 = buf1 || 'и';
            ELSE IF (raz > 1) THEN buf1 = buf1 || 'а';
          END ELSE
            IF (raz > 1) THEN buf1 = buf1 || 'ів';
        END
        ELSE IF (:lang = 'RU') THEN BEGIN
          IF (i = 1) THEN BEGIN
            IF (raz = 1) THEN buf1 = buf1 || 'а';
          END ELSE
          IF (i IN (2,3,4)) THEN BEGIN
            IF (raz = 1) THEN buf1 = buf1 || 'и';
            ELSE IF (raz > 1) THEN buf1 = buf1 || 'а';
          END ELSE
            IF (raz > 1) THEN buf1 = buf1 || 'ов';
        END
        buf = buf || ' ' || buf1;
      END
    END ELSE
      buf = '';
 
    /* Присоединяем обработанную триаду к результату */
    IF (curr_str != '' AND buf != '') THEN buf = buf || ' ';
    curr_str = buf || curr_str;
    /* Переходим к следующей триаде */
    val_str = LEFT(val_str, CHAR_LENGTH(val_str)-3);
    /* Увеличиваем счётчик разряда */
    raz = raz + 1;
  END
 
  /* Припысываем знак */
  curr_str = sign_of_val || curr_str;
  /* Делаем первую букву прописной */
  curr_str = UPPER(SUBSTRING(curr_str FROM 1 FOR 1)) || SUBSTRING(curr_str FROM 2);
 
  /* Флаг "показать название валюты" */
  IF (showcurrency != 0) THEN
  BEGIN
    IF (curr_str != '' ) THEN
      curr_str = curr_str || ' '||curr_abr||' ';
 
    curr_str = curr_str || cents || ' коп.';
  END
 
  suspend;
END^
 
SET TERM ; ^
 
GRANT EXECUTE ON PROCEDURE CURRENCYSTR TO SYSDBA;

См. также

Источник

Форум: sql.ru,

Автор: WildSery, (Sp1r1t добавил поддержку украинской валюты)

Пост: http://sql.ru/forum/actualthread.aspx?tid=628590&pg=-1#6717281

Обсуждение

Дмитрий, 2009/11/17 02:03

ХМ…. не компилится… Говорит, что функции «position» не бывает!;)

Attid, 2009/11/17 05:30

обновите сервер до версии 2,1

Только авторизованные участники могут оставлять комментарии.
sql003.summa_propisju.txt · Последние изменения: 2011/07/26 01:49 — peaktop