NEW CONTEST: Useful and Cool Stored Procedures

19 views
Skip to first unread message

IBSurgeon

unread,
Mar 31, 2010, 5:32:11 AM3/31/10
to MindTheBird!
Hello All,

Are you true master in Firebird SQL? Participate in Stored Procedures
contest and win valuable prizes!

Participants should submit stored procedure in pure Firebid SQL and
embedded functions (SDF) only which performs some common task(s) -
virtually anything any useful tasks.

It can be implementations of some mathematics transformations, or
transforming numeric representation of number into words (like input =
21, output = "twenty one"), or anything that demonstrates the power
and flexibility of Firebird stored procedures.

We'll choose the most powerful and interesting stored procedures.
There will be 3 winners, each of them will receive tool by his choice
from the pool of prizes from MindTheBird sponsors:
http://www.mindthebird.com/benefits.html.


All procedures should be submited under Creative Commons or Mozilla
Public License or Apache License. Submitter must be the author of the
procedure.

All procedures with short description and reference to the author will
be published at www.mindthebird.com

Please submit demo SQL scripts with stored procedures' texts to sp at
mindthebird.com or right here in the group. Please notice that demo
SQL script should work out-of-the-box to create necessary objects and
demonstrate the value of procedure.

Željko Cvijanović

unread,
Mar 31, 2010, 2:54:22 PM3/31/10
to mindt...@googlegroups.com
Hello,

Where do I provide a function "LatinToCir" (translation of Latin into Cyrillic) and "letters" (value brojacanu write letters) source code in pascal - Delphi

Zeljko Cvijanovic
ZELJUS szd
Teslić - Republika Srpska BiH
http://sites.google.com/site/zeljusorg/

2010/3/31 IBSurgeon <ibsu...@gmail.com>


--
To unsubscribe, reply using "remove me" as the subject.

Carlos H. Cantu

unread,
Mar 31, 2010, 3:01:11 PM3/31/10
to mindt...@googlegroups.com
The procedures for this contest should be in PSQL, not Delphi/Pascal.

Carlos

2010/3/31 Željko Cvijanović <cvze...@gmail.com>

IBSurgeon

unread,
Mar 31, 2010, 3:13:57 PM3/31/10
to MindTheBird!
We have first submission in pure SQL from Sergey Smirnov, Russia

His procedure #1 transforms BLOB filled with comma-separated numerics
into the recordset.

SET TERM ^ ;

create or alter procedure LIST_TO_ROWS (
LST blob sub_type 1 segment size 80)
returns (
ID integer)
AS
declare pos_ int;
declare offset int = 1;
declare beg int;
declare buf varchar(30100);
begin
while (0=0) do begin
buf = substring(lst from offset for 30100);
pos_ = 1; beg = 1;
while (pos_ <= char_length(buf) and pos_ <= 30000) do begin
if (substring(buf from pos_ for 1) = ',') then begin
if (pos_ > beg) then
id = substring(buf from beg for pos_ - beg);
else
id = null;
suspend;
beg = pos_ + 1;
end
pos_ = pos_ + 1;
end
if (offset + pos_ - 2 = char_length(lst)) then leave;
offset = offset + beg - 1;
if (offset > char_length(lst)) then leave;
end

if (pos_ > beg) then
id = substring(buf from beg for pos_ - beg);
else
id = null;
suspend;
end^

SET TERM ; ^

The second procedure transforms numeric currency value into Russian
written representation of the numeric:
SET TERM ^ ;

create or alter procedure CURRENCYSTR (
VAL numeric(15,2),
SHOWCURRENCY integer)
returns (
CURR_STR varchar(1000))
AS
declare razryad varchar(50);
declare razryad_idx varchar(28);
declare hundreds varchar(64);
declare hundreds_idx varchar(30);
declare tens varchar(69);
declare tens_idx varchar(40);
declare ones varchar(138);
declare ones_idx varchar(100);

declare sign_of_val varchar(6);
declare raz int;
declare cents varchar(3);
declare val_str varchar(20);
declare num varchar(20);
declare i int;
declare buf varchar(200);
declare buf1 varchar(200);

begin
/* Константы */
razryad_idx = /* 2.2 */ '010001050607130821082911';
razryad = 'тысячмиллионмиллиардтриллионквадриллион';
hundreds_idx = /* 2.1 */ '010013046106169257328407479569';
hundreds =
'стодвеститристачетырестапятьсотшестьсотсемьсотвосемьсотдевятьсот';
tens_idx = /* 2.2 */ '0100010001080908170522093110410950116109';
tens =
'двадцатьтридцатьсорокпятьдесятшестьдесятсемьдесятвосемьдесятдевяносто';
ones_idx = /* 3.2 */
'0010000100001000010300406010040140501904023060290603506041110521006210072120841009411105101151212712';
ones =
'тричетырепятьшестьсемьвосемьдевятьдесятьодиннадцатьдвенадцатьтринадцатьчетырнадцатьпятнадцатьшестнадцатьсемнадцатьвосемнадцатьдевятнадцать';

if (ShowCurrency is null) then ShowCurrency = 0;
curr_str = '';

/* Смотрим знак */
if (val < 0) then begin
sign_of_val = 'минус ';
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), (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 (raz = 1) then buf1 = 'одна'; else buf1 = 'один';
end else
if (i = 2) then begin
if (raz = 1) then buf1 = 'две'; else buf1 = 'два';
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 (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 || 'ов';
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 = 1) then
curr_str = curr_str || ' руб. ' || cents || ' коп.';

suspend;
end^

SET TERM ; ^


Carlos H. Cantu

unread,
Mar 31, 2010, 3:20:00 PM3/31/10
to mindt...@googlegroups.com
May I suggest that submissions also should include example of running the procedure and the results?

Carlos

2010/3/31 IBSurgeon <ibsu...@gmail.com>

Carlos H. Cantu

unread,
Mar 31, 2010, 3:21:36 PM3/31/10
to mindt...@googlegroups.com
One more thing... comments in the code should be in English, or only "native people" will be able to understand (afaiu, this is international contest, isn't it? ;-)

Codebue Fabio - P-Soft

unread,
Mar 31, 2010, 7:05:43 PM3/31/10
to mindt...@googlegroups.com

Hi,

I just sent another mail to mine 400 users of italian community with stored procedure and article contest

 

PS benefits page of mindthebird.com have an error:

particpants  --> partecipants

 

 

Codebue Fabio

.--------------------------------.

P-Soft di Codebue Fabio

via Nuova, 9

24060 Tavernola B.sca - BG

Web : www.p-soft.biz

EMail: f.co...@p-soft.biz

 

Željko Cvijanović

unread,
Apr 1, 2010, 7:36:41 AM4/1/10
to mindt...@googlegroups.com
Firebird 1.5

----------------------------------------------------------
external function:

DECLARE EXTERNAL FUNCTION mod 
INTEGER, INTEGER
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'IB_UDF_mod' MODULE_NAME 'ib_udf';


DECLARE EXTERNAL FUNCTION substr 
CSTRING(255), SMALLINT, SMALLINT
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';

----------------------------------------------------------
Procedure:

CREATE or ALTER PROCEDURE "KontrolaJMBG" (
    "cJMBG" CHAR (13) CHARACTER SET WIN1250)
RETURNS (
    "bVrati" CHAR (5) CHARACTER SET WIN1250)
AS
declare variable "nSum"  integer;
declare variable "nCtrl" integer;
declare variable "nX"    integer;
declare variable "n1"    integer;
declare variable "n2"    integer;
declare variable "n3"    integer;
declare variable "n4"    integer;
declare variable "n5"    integer;
declare variable "n6"    integer;
declare variable "n7"    integer;
declare variable "n8"    integer;
declare variable "n9"    integer;
declare variable "n10"   integer;
declare variable "n11"   integer;
declare variable "n12"   integer;
declare variable "n13"   integer;
begin
 /* KontrolaJMBG */

     "bVrati" = 'True';

     
        if (CAST(SubStr("cJMBG", 1, 2) as integer) > 31) then
            "bVrati" = 'False';
        else
        if (CAST(SubStr("cJMBG", 3, 4) as integer) > 12) then
            "bVrati" = 'False';
        else
        If ("bVrati" = 'True') then begin
           "n1" = CAST(SubStr("cJMBG", 1, 1) as integer);
           "n2" = CAST(SubStr("cJMBG", 2, 2) as integer);
           "n3" = CAST(SubStr("cJMBG", 3, 3) as integer);
           "n4" = CAST(SubStr("cJMBG", 4, 4) as integer);
           "n5" = CAST(SubStr("cJMBG", 5, 5) as integer);
           "n6" = CAST(SubStr("cJMBG", 6, 6) as integer);
           "n7" = CAST(SubStr("cJMBG", 7, 7) as integer);
           "n8" = CAST(SubStr("cJMBG", 8, 8) as integer);
           "n9" = CAST(SubStr("cJMBG", 9, 9) as integer);
           "n10"= CAST(SubStr("cJMBG", 10, 10)as integer);
           "n11"= CAST(SubStr("cJMBG", 11, 11) as integer);
           "n12"= CAST(SubStr("cJMBG", 12, 12) as integer);
           "n13"= CAST(SubStr("cJMBG", 13, 13) as integer);

           "nSum" = "n1" * 7 + "n2" * 6 + "n3" * 5 + "n4" * 4 + "n5" * 3 + "n6" * 2 +
           "n7" * 7 + "n8" * 6 + "n9" * 5 + "n10" * 4 + "n11" * 3 + "n12" * 2;

           "nCtrl" = 11 - MOD ("nSum", 11);
           
          /* "bVrati" = "nSum"; */
           IF ("nCtrl" < 10) then
              "nX" = "nCtrl";
           else
               "nX" = 0;
           
          IF ("n13" <> "nX") then "bVrati" = 'False';
        end

     SUSPEND;
end

--------------- Test
select "sRadnik"."PrezimeIme", "sRadnik"."RodjenDatum", "sRadnik".jmbg,
(select "KontrolaJMBG"."bVrati"
  from "KontrolaJMBG"("sRadnik".jmbg)) as "TestJMBG"
from "sRadnik"

PrezimeIme RodjenDatum JMBG TestJMBG
BAČIĆ RADOSLAV            23.06.1971      2306971123590     True
BAČIĆ SMILJANA            03.01.1973      0301973128620     True
BJELČEVIĆ RADE            19.06.1970      1906971122624     False
BLAŽANOVIĆ BORISLAV            13.03.1959      1303959122624     True
SIMIĆ MIRJANA                    01.10.1968      0110968128590     True
BORIŠIĆ MILE                    04.03.1959      0403954123585     True

Milan Babuskov

unread,
Apr 1, 2010, 8:28:10 AM4/1/10
to mindt...@googlegroups.com
2010/4/1 Željko Cvijanović <cvze...@gmail.com>:
> Firebird 1.5

Hi Zeljko,

I like you procedure, it is usable, but it would be nice if you used
Firebird 2.5 because this campaign is about promoting it.

> ----------------------------------------------------------
> external function:
> DECLARE EXTERNAL FUNCTION mod
> INTEGER, INTEGER
> RETURNS DOUBLE PRECISION BY VALUE
> ENTRY_POINT 'IB_UDF_mod' MODULE_NAME 'ib_udf';
>
> DECLARE EXTERNAL FUNCTION substr
> CSTRING(255), SMALLINT, SMALLINT
> RETURNS CSTRING(255) FREE_IT
> ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';

MOD is internal function in Firebird 2.x, so no need to declare.
Instead of SUBSTR, you can use built-in SUBSTRING which is
multi-byte-character aware.

Also, a description for procedure would be nice, for those who don't
know what is JMBG.

--
Milan Babuskov
http://www.flamerobin.org

Željko Cvijanović

unread,
Apr 1, 2010, 10:45:05 AM4/1/10
to mindt...@googlegroups.com
OK, Pozdrav,


Firebird 2.5

-----------------------
JMBG - ID number is a unique identification number of people in Bosnia and Herzegovina, Central Register of water (CIPS).

It consists of the date of birth and codes assigned by the Ministry of Internal posloava

has 13 digits

sampl:
 23.06.1971. 

2306971xxxxxx

--------------------------------------------

CREATE PROCEDURE "KontrolaJMBG" (
    "cJMBG" CHAR (13) CHARACTER SET WIN1250)
RETURNS (
    "bVrati" CHAR (5) CHARACTER SET WIN1250)
ASdeclare variable "nSum"  integer;
declare variable "nCtrl" integer;
declare variable "nX"    integer;
declare variable "n1"    integer;
declare variable "n2"    integer;
declare variable "n3"    integer;
declare variable "n4"    integer;
declare variable "n5"    integer;
declare variable "n6"    integer;
declare variable "n7"    integer;
declare variable "n8"    integer;
declare variable "n9"    integer;
declare variable "n10"   integer;
declare variable "n11"   integer;
declare variable "n12"   integer;
declare variable "n13"   integer;
begin
 /* KontrolaJMBG */

     "bVrati" = 'True';


        if (CAST(substring("cJMBG" from 1 for 2) as integer) > 31) then
            "bVrati" = 'False';
        else
        if (CAST(Substring("cJMBG" from 3 for 2) as integer) > 12) then
            "bVrati" = 'False';
        else
        If ("bVrati" = 'True') then begin
           "n1" = CAST(Substring("cJMBG" from 1 for 1) as integer);
           "n2" = CAST(Substring("cJMBG" from 2 for 1) as integer);
           "n3" = CAST(Substring("cJMBG" from 3 for 1) as integer);
           "n4" = CAST(Substring("cJMBG" from 4 for 1) as integer);
           "n5" = CAST(Substring("cJMBG" from 5 for 1) as integer);
           "n6" = CAST(Substring("cJMBG" from 6 for 1) as integer);
           "n7" = CAST(Substring("cJMBG" from 7 for 1) as integer);
           "n8" = CAST(Substring("cJMBG" from 8 for 1) as integer);
           "n9" = CAST(Substring("cJMBG" from 9 for 1) as integer);
           "n10"= CAST(Substring("cJMBG" from 10 for 1)as integer);
           "n11"= CAST(Substring("cJMBG" from 11 for 1) as integer);
           "n12"= CAST(Substring("cJMBG" from 12 for 1) as integer);
           "n13"= CAST(Substring("cJMBG" from 13 for 1) as integer);

Željko Cvijanović

unread,
Apr 2, 2010, 6:57:09 AM4/2/10
to mindt...@googlegroups.com
I've created a procedure that the amount of numbers, letters


Firebird-2.5.0.25920-0_Win32_embed_RC2

PROCEDURE "Slovima"
+++++++++++++++++++++++++++++++++++++++
CALL:

SELECT
  cast("Faktura"."Iznos" as decimal(15,0)) as "Iznos",
  (select "Slovima"."IznosSlovima"
   from "Slovima"(cast("Faktura"."Iznos" as decimal(15,0))))
FROM
  "Faktura"

result:

Iznos     IznosSlovima
2.694,000 dvijehiljadešeststotinadevedesetčetiri
1.559,000 jednahiljadapetstotinapedesetdevet
  297,000 dvijestotinedevedesetsedam
4.455,000 četirihiljadečetiristotinepedesetpet
3.636,000 trihiljadešeststotinatridesetšest

+++++++++++++++++++++++++++++++++++++++
1. Declared external function

DECLARE EXTERNAL FUNCTION div
INTEGER, INTEGER
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'IB_UDF_div' MODULE_NAME 'ib_udf';


DECLARE EXTERNAL FUNCTION lpad
CSTRING(255) NULL, INTEGER, CSTRING(1) NULL
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'IB_UDF_lpad' MODULE_NAME 'ib_udf'; 


DECLARE EXTERNAL FUNCTION STRLEN 
    CSTRING (32767)
    RETURNS INTEGER BY VALUE
    ENTRY_POINT 'IB_UDF_strlen' MODULE_NAME 'ib_udf';


DECLARE EXTERNAL FUNCTION SUBSTR 
    CSTRING (80),
    SMALLINT,
    SMALLINT
    RETURNS CSTRING (14) FREE_IT
    ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';
+++++++++++++++++++++++++++++++++
2. Create table

CREATE TABLE "sSlovima" 
(
  "SlovimaID" SMALLINT NOT NULL,
  "Slovima" VARCHAR(20) CHARACTER SET WIN1250 NOT NULL,
CONSTRAINT "PK_sSlovima" PRIMARY KEY ("SlovimaID")
);

3. insert itno to table "sSlovima"

INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '1', '');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '2', 'jedan');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '3', 'dva');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '4', 'tri');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '5', 'èetiri');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '6', 'pet');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '7', 'šest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '8', 'sedam');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '9', 'osam');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '10', 'devet');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '11', 'deset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '12', 'jedanaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '13', 'dvanaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '14', 'trinaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '15', 'èetrrnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '16', 'petnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '17', 'šesnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '18', 'sedamnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '19', 'osamnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '20', 'devetnaest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '21', 'dvadeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '22', 'trideset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '23', 'èetrdeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '24', 'pedeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '25', 'šezdeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '26', 'sedamdeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '27', 'osamdeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '28', 'devedeset');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '31', '');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '32', 'jedna');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '33', 'dvije');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '34', 'tri');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '35', 'èetiri');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '36', 'pet');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '37', 'šest');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '38', 'sedam');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '39', 'osam');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '40', 'devet');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '41', 'stotina');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '42', 'stotine');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '43', 'hiljada');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '44', 'hiljade');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '45', 'milijun');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '46', 'milijuna');


+++++++++++++++++++++++++++++++++
4. create procedure 

CREATE PROCEDURE "Slovima" (
    "Iznos" NUMERIC (15, 0))
RETURNS (
    "IznosSlovima" VARCHAR (200) CHARACTER SET WIN1250)
AS /*  */
declare variable "cizn" varchar(15);
declare variable "s" varchar(200);
declare variable "xx" varchar(15);
declare variable "x" varchar(15);
declare variable "j" smallint;
declare variable "q" smallint;
declare variable "xi" integer;
declare variable "code" integer;

begin
  "cizn" = cast(:"Iznos" as varchar(15));

  "cizn" = LPAD ("cizn", 15, '0');
  "s" = ''; "j" = 1;
  
  "q" = 1;
  while ("q" <= 5) do begin
    "xx" = substr("cizn", :"j", :"j"+ 2);
   /* "IznosSlovima" = "xx"; suspend; ispis brojeva */
    
    if ("xx" <> '000') then begin
      "x" = substr("xx", 1, 1);
      "xi" = cast(:"x" as integer);

      if ("xi" > 0) then begin    /* stotine */
         if ("xi" >= 1) then
            if ("xi" < 3) then
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = 31 + :"xi")
              into :"s";
            else 
             select :"s"||"sSlovima"."Slovima"
             from "sSlovima"
             where ("sSlovima"."SlovimaID" = 1 + :"xi")
             into :"s";

            if (("xi" > 1) AND ("xi" < 5))  then
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = 42)
              into :"s";
            else
             select :"s"||"sSlovima"."Slovima"
             from "sSlovima"
             where ("sSlovima"."SlovimaID" = 41)
             into :"s";
     end /* ---------if ("xi" > 0) then begin */

      "x" = substr("xx", 2, 3);
      "xi" = cast(:"x" as integer);
      
      if (div("xi", 10) = 1) then /* desetice i jedinice*/
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = :"xi" + 1)
              into :"s";
      else begin 
        if ("xi" > 10) then
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = 19 + div(:"xi", 10))
              into :"s";
              
        if (("xx" <> '001') or ('' <> "s") or ("j" = 13)) then
           "xi" = "xi" - (div("xi", 10) * 10);
           
        if (("j" = 10) or ("j" = 4)) then
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = 31 + :"xi")
              into :"s";
        else
              select :"s"||("sSlovima"."Slovima")
              from "sSlovima"
              where ("sSlovima"."SlovimaID" = 1 + :"xi")
              into :"s";
      end
     /* "s" = "s" ||' ' - razmak  000 000 000; */
     
     if ("j" = 1) then if ("xi" <> 1) then
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 50)
                          into :"s";
                       else
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 49)
                          into :"s";
     else if ("j" = 4) then if ("xi" = 1) then
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 47)
                          into :"s";
                       else if (("xi" < 1) or ("xi" > 4)) then
                               select :"s"||("sSlovima"."Slovima")
                               from "sSlovima"
                               where ("sSlovima"."SlovimaID" = 48)
                               into :"s";
                            else
                                select :"s"||("sSlovima"."Slovima")
                                from "sSlovima"
                                where ("sSlovima"."SlovimaID" = 54)
                                into :"s";
     else if ("j" = 7) then if ("xi" <> 1) then
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 46)
                          into :"s";
                       else
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 45)
                          into :"s";
     else if ("j" = 10) then if (("xi" < 2) or ("xi" > 4)) then
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 43)
                          into :"s";
                       else
                          select :"s"||("sSlovima"."Slovima")
                          from "sSlovima"
                          where ("sSlovima"."SlovimaID" = 44)
                          into :"s";
    end /* ---------if ("xx" <> '000') then begin */

    "j" = "j" + 3;
    "q" = "q" + 1;
  end

 "IznosSlovima" = "s";
 Suspend;
end

++++++++++++++++++++++++++++++++++++++++

Željko Cvijanović

unread,
Apr 2, 2010, 7:05:00 AM4/2/10
to mindt...@googlegroups.com
add table "sSlovima"

INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '47', 'milijarda');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '48', 'milijardi');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '49', 'bilijun');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '50', 'bilijuna');
INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '54', 'milijarde');

Milan Babuskov

unread,
Apr 2, 2010, 7:31:15 AM4/2/10
to mindt...@googlegroups.com
Hi Zeljko,

2010/4/2 Željko Cvijanović <cvze...@gmail.com>:


> add table "sSlovima"
> INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '47', 'milijarda');
> INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '48', 'milijardi');
> INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '49', 'bilijun');
> INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '50', 'bilijuna');
> INSERT INTO "sSlovima" ("SlovimaID", "Slovima") VALUES ( '54', 'milijarde');

This is really cool. Did you consider to also add an English version
(just using different INSERTs)?

Željko Cvijanović

unread,
Apr 2, 2010, 8:07:46 AM4/2/10
to mindt...@googlegroups.com
I'm bad with English, so the problems do not know how it would look like
a translation using Google Translator


Zeljko Cvijanovic
ZELJUS szd
Teslić - Republika Srpska BiH
http://sites.google.com/site/zeljusorg/



This is really cool. Did you consider to also add an English version
(just using different INSERTs)?
- Сакриј наведени текст -

IBSurgeon

unread,
Apr 5, 2010, 10:28:42 AM4/5/10
to MindTheBird!
We have submission of collection of stored procedures for mathematics
operations (comments are in English and in Russian):

/*
Decimal long-string arithmetic procedures. Decimal point is allowed,
signs (+/-) are not allowed.

Useful thing for study and reminiscences, not for production
releases.

You may use this code without any restrictions, but you must mention
me.
MindTheBird - and mind pizmon too.

Процедуры десятичной длинностроковой точной арифметики разработаны
в исторически-юмористически-дидактических целях. Поддерживается
десятичная точка, не поддерживаются знаки (+/-).

Автор подозревает о существовании ряда полезных нововведений,
позволяющих "этим вот" больше не заниматься. Но автор обращает
внимание благосклонной аудитории на следующее:

1. Как не хватало нам этих полезных нововведений в те далекие
годы, когда
Firebird был Interbase, а ОС Novell Netware была тем, чем она
была! И
ничего, почти все выжили.

2. Умение, как говорил шахматист Остап Бендер, "с ничтожными
силами овладеть
всей доской" стимулирет интеллектуальную смелость, необходимую
для профессии программиста. Изучать древний опыт также
полезно.
"Чтобы стоять, я должен держаться корней".

Допускается любое использование этих процедур при упоминании автора.

(с) pizmon

*/

set term ^;

/*
this extracts from string "s" a digit defined by template "templ".
Nowadays we've got "substring" to do it without kinking our brain.

эта процедура вычленяет из строки s разряд, определяемый шаблоном
templ.
для этого в наше время используется substring.
*/
create procedure dig
(
s varchar(1000),
templ varchar(1000)
)
returns
(
result integer
)
as
begin
if (s like '%' || '0' || templ) then
result = 0;
else if (s like '%' || '1' || templ) then
result = 1;
else if (s like '%' || '2' || templ) then
result = 2;
else if (s like '%' || '3' || templ) then
result = 3;
else if (s like '%' || '4' || templ) then
result = 4;
else if (s like '%' || '5' || templ) then
result = 5;
else if (s like '%' || '6' || templ) then
result = 6;
else if (s like '%' || '7' || templ) then
result = 7;
else if (s like '%' || '8' || templ) then
result = 8;
else if (s like '%' || '9' || templ) then
result = 9;
else if (s like '%' || '.' || templ) then
result = -1;
else
result = null;
suspend;
end
^

/*
this divides string "s" by ten shifting decimal point.

эта процедура делит строку s на 10 методом сдвига десятичной точки.
*/
create procedure strshift
(
s varchar(1000)
)
returns
(
result varchar(1000)
)
as
declare variable templ varchar(1000);
declare variable d integer;
declare variable n integer;
begin
templ = '';
result = '';
if (s not like '%.%') then
n = 1;
else
n = 0;
while (1=1) do
begin
select result from dig(:s, :templ) into :d;
if (d is null) then
begin
if (result like '.%') then
result = '0' || result;
suspend;
exit;
end
else if (d = -1) then
n = 1;
else
begin
result = d || result;
if (n = 1) then
begin
result = '.' || result;
n = 0;
end
end
templ = templ || '_';
end
end
^

/*
this reconciles strings "s1" and "s2" to make them agree with
decimal point
position.

эта процедура приводит строки s1 и s2 к виду, в котором десятичная
точка
стоит в одном и том же разряде
*/
create procedure strnormalize
(
s1 varchar(1000),
s2 varchar(1000)
)
returns
(
result1 varchar(1000),
result2 varchar(1000)
)
as
declare variable templ1 varchar(1000);
declare variable n1 integer;
declare variable templ2 varchar(1000);
declare variable n2 integer;
begin
templ1 = '';
n1 = 0;
if (s1 like '%.%') then
while (s1 not like '%.' || templ1) do
begin
templ1 = templ1 || '_';
n1 = n1 + 1;
end
templ2 = '';
n2 = 0;
if (s2 like '%.%') then
while (s2 not like '%.' || templ2) do
begin
templ2 = templ2 || '_';
n2 = n2 + 1;
end
result1 = s1;
result2 = s2;
while (n1 > n2) do
begin
if (n2 = 0) then
result2 = result2 || '.';
result2 = result2 || '0';
n2 = n2 + 1;
end
while (n2 > n1) do
begin
if (n1 = 0) then
result1 = result1 || '.';
result1 = result1 || '0';
n1 = n1 + 1;
end
suspend;
end
^
/*
this adds string "s1" to string "s2" using old-school "column"
method.

эта процедура складывет строки s1 и s2 "в столбик".
*/
create procedure stradd
(
s1 varchar(1000),
s2 varchar(1000)
)
returns
(
result varchar(1000)
)
as
declare variable templ varchar(1000);
declare variable carry integer;
declare variable d1 integer;
declare variable d2 integer;
begin
select result1, result2 from strnormalize(:s1, :s2) into :s1, :s2;
templ = '';
result = '';
carry = 0;
while (1=1) do
begin
select result from dig(:s1, :templ) into :d1;
select result from dig(:s2, :templ) into :d2;
if (d1 is null and d2 is null) then
begin
if (carry <> 0) then
result = carry || result;
suspend;
exit;
end
else
begin
if (d1 = -1 or d2 = -1) then
result = '.' || result;
else
begin
if (d1 is not null) then
carry = carry + d1;
if (d2 is not null) then
carry = carry + d2;
result = (carry - (carry / 10) * 10) || result;
carry = carry / 10;
end
end
templ = templ || '_';
end
end
^
/*
this multiplies string "s" by "dig" using repeated additions.

эта процедура умножает строку s на целое число dig многократным
сложением
*/

create procedure strdigmul
(
s varchar(1000),
dig integer
)
returns
(
result varchar(1000)
)
as
begin
result = '0';
while (dig > 0) do
begin
select result from stradd(:result, :s) into :result;
dig = dig - 1;
end
suspend;
end
^

/*
this subtracts string "s2" from string "s1" using old-school
"column" method.

эта процедура вычитает строку s2 из строки s1 "в столбик".
*/

create procedure strsub
(
s1 varchar(1000),
s2 varchar(1000)
)
returns
(
result varchar(1000)
)
as
declare variable templ varchar(1000);
declare variable carry integer;
declare variable n integer;
declare variable d1 integer;
declare variable d2 integer;
begin
select result1, result2 from strnormalize(:s1, :s2) into :s1, :s2;
templ = '';
result = '';
carry = 0;
while (1=1) do
begin
select result from dig(:s1, :templ) into :d1;
select result from dig(:s2, :templ) into :d2;
if (d1 is null and d2 is null) then
begin
suspend;
exit;
end
else
begin
if (d1 = -1 or d2 = -1) then
result = '.' || result;
else
begin
if (d1 is not null) then
carry = carry + d1;
if (d2 is not null) then
carry = carry - d2;
n = 0;
while (carry < 0) do
begin
n = n + 1;
carry = carry + 10;
end
result = (carry - (carry / 10) * 10) || result;
carry = (carry / 10) - n;
end
end
templ = templ || '_';
end
end
^

/*

this multiplies string "s1" by "s2" using old-school "column"
method.

эта процедура умножает строку s1 на строку s2 "в столбик".
*/

create procedure strmul
(
s1 varchar(1000),
s2 varchar(1000)
)
returns
(
result varchar(1000)
)
as
declare variable n integer;
declare variable d2 integer;
declare variable templ varchar(1000);
declare variable frac varchar(1000);
declare variable mul varchar(1000);
begin
templ = '';
frac = '0';
n = 0;
result = '0';
mul = s1;
while (1=1) do
begin
select result from dig(:s2, :templ) into :d2;
if (d2 is null) then
begin
select result from stradd(:frac, :result) into :result;
suspend;
exit;
end
if (d2 <> -1) then
begin
select result from stradd((select result from
strdigmul(:mul, :d2)), :result) into :result;
select result from strdigmul(:mul, 10) into :mul;
n = n + 1;
end
else
begin
frac = result;
while (n > 0) do
begin
select result from strshift(:frac) into :frac;
n = n - 1;
end
result = '0';
mul = s1;
end
templ = templ || '_';
end
end
^

/*

this compares strings "s1" and "s2". Unsignificant zeroes are
allowed.

эта процедура сравнивает строку s1 со строкой s2. Обрабатываются
ситуации лидирующих/завершающих нулей
*/

create procedure strcomp
(
s1 varchar(1000),
s2 varchar(1000)
)
returns
(
result integer
)
as
declare variable templ varchar(1000);
declare variable l1 integer;
declare variable l2 integer;

begin
select result1, result2 from strnormalize(:s1, :s2) into :s1, :s2;

if (s1 = s2) then
result = 0;
else
begin

l1 = 0;
templ = '';
while (s1 not like templ) do
begin
templ = templ || '_';
l1 = l1 + 1;
end

l2 = 0;
templ = '';
while (s2 not like templ) do
begin
templ = templ || '_';
l2 = l2 + 1;
end

while (l1 < l2) do
begin
s1 = '0' || s1;
l1 = l1 + 1;
end

while (l2 < l1) do
begin
s2 = '0' || s2;
l2 = l2 + 1;
end

if (s1 = s2) then
result = 0;
else if (s1 < s2) then
result = -1;
else
result = 1;
end
suspend;
end
^

/*
this calculates factorial of string "s"

эта процедура возвращает факториал строки s
*/

create procedure strfactorial
(
s varchar(1000)
)
returns
(
result varchar(1000)
)
as
declare variable cmp integer;
begin
result = s;
while (1=1) do
begin
select result from strcomp(:s, '1') into :cmp;
if (cmp = 0) then
begin
suspend;
exit;
end
else
begin
select result from strsub(:s, '1') into :s;
select result from strmul(:result, :s) into :result;
end
end
end
^

/*
this raises string "s" to "dig" power using repeated
multiplications.

эта процедура возводит строку s в целочисленную степень методом
многокоратного умножения.
*/
create procedure strdigpwr
(
s varchar(1000),
dig integer
)
returns
(
result varchar(1000)
)
as
begin
result = '1';
while (dig > 0) do
begin
select result from strmul(:result, :s) into :result;
dig = dig - 1;
end
suspend;
end
^

/*
this divides string "s1 " by string "s2". "Maxdigits" limits amount
of
decimal digits in resulting periodical fraction (if any).

эта процедура делит строку s1 на строку s2. Параметр maxdigits
ограничивает количество знаков в случае,
если результатом деления является периодическая десятичная дробь.
*/

create procedure strdiv
(
s1 varchar(1000),
s2 varchar(1000),
maxdigits integer
)
returns
(
result varchar(1000)
)
as
declare variable n integer;
declare variable cmp integer;
declare variable m integer;
declare variable att varchar(1000);
declare variable d integer;
declare variable len integer;
declare variable cond integer;
declare variable divisor varchar(1000);

begin

divisor = s2;

n = 0;
cmp = 1;
m = 1;

while (cmp > 0) do
begin
select result from strcomp(:s1, :s2) into :cmp;
if (cmp > 0) then
begin
select result from strdigmul(:s2, 10) into :s2;
n = n + 1;
m = m * 10;
end
else if (cmp = 0) then
begin
result = m;
suspend;
exit;
end
end

select result from strshift(:s2) into :s2;

result = '';
cmp = 1;
len = 0;
while (1=1) do
begin
len = len + 1;

if (len = maxdigits) then
begin
suspend;
exit;
end

if (len = n + 1) then
begin
if (result = '') then
result = '0';
result = result || '.';
end

d = 9;
while (d >= 0) do
begin
select result from strdigmul(:s2, :d) into :att;
select result from strcomp(:s1, :att) into :cmp;
if (cmp < 0) then
d = d - 1;
else
begin
select result from strsub(:s1, :att) into :s1;

select result from strcomp(:s2, :divisor) into :cond;

result = result || d;
d = -1;
if (cmp = 0 and cond = 0) then
begin
suspend;
exit;
end
select result from strshift(:s2) into :s2;
end
end

end

end
^

/*

ladies and gentelmen! Now here the exponent! An exponent is
calulated using
Taylor series.

Барабанная дробь: то, ради чего всё затевалось. Экспонента
рассчитывается по ряду Тейлора.
*/

create procedure strexp
(
s varchar(1000),
maxdigits integer,
members integer
)
returns
(
result varchar(1000)
)
as
declare variable n integer;
declare variable p varchar(1000);
declare variable f varchar(1000);
begin
p = '1';
f = '1';
n = 0;
result = '1';
while (n < members) do
begin
n = n + 1;
select result from strmul(:p, :s) into :p;
select result from strdigmul(:f, :n) into :f;
select result from stradd(:result, (select result from
strdiv(:p, :f, :maxdigits))) into :result;
end
suspend;
end
^

/*
we have to test it!

неужели мы это не проверим?
*/

select result from strexp('1', 10, 20)

/*

The result is 2.718281823. Real value is e=2.718281828, we've got
an
error in last digit. Not bad, yeah?

Exponent opens a door to high math for us, but it is about math,
not about Firebird.

Thank you.

результат: 2.718281823
насколько я помню, e=2.718281828, то есть ошибка в последнем знаке.
Неплохо, ведь правда?

Имея на руках экспоненту положительных чисел, перед нами открыты все
двери.
Дальнейшее имеет отношение к учебнику математики за седьмой класс,
но, увы,
уже не имеет никакого отношения к Firebird.

Спасибо за внимание.
*/

^
set term ;^


Reply all
Reply to author
Forward
0 new messages