Kwota słownie w SQL
Jak sobie z tym poradzić
Problem zamiany liczby na jej tekstowy odpowiednik nie jest zadaniem trywialnym. Przyjęło się, że na różnych dokumentach, głównie finansowych, oprócz kwoty słownie, pojawia się reprezentujący tę kwotę tekst. Mamy zatem tysiąc dwieście czternaście uzupełniające liczbę 1214, czy też milion dwieście zamiast 1200000. Dla tych, którzy przywiązani są do bazy danych przydałaby się jakaś rozsądna metoda. Nigdzie takiej nie znalazłem, więc postanowiłem zaprezentować swoje rozwiązanie. Odmiana liczebników to jeden z bardziej niewdzięcznych obszarów języka polskiego. Przede wszystkim dlatego, że niewiele jest reguł, które pozwalają automatycznie takie liczebniki wygenerować. Liczby od 0 do 19 i każde pełne dziesiątki po prostu mają swój unikatowy odpowiednik tekstowy. W związku z powyższym nie da się uwspólnić 18 (jeden osiem) i 19 (jeden dziewięć) pomimo tego, że liczby mają po jednej dziesiątce. Ta własność wspólna nic nam nie daje. Mamy osiemnaście i dziewiętnaście. Te składniki (osiemnaście i dziewiętnaście) pojawiają się po raz kolejny dopiero w liczbie... 18000. Niestety, ale nie ma innego wyjścia - sporą cześć wartości słownych należy umieścić w tabeli. Można oczywiście to samo zrobić przy pomocy instrukcji CASE, ale takie rozwiązanie uznałem za moało przejrzyste.
Pomocnicza tabela liczebników
Przyjrzyjmy się zatem wspomnianej tabeli pomocniczej:
CREATE TABLE Liczebniki ( Rzad char(1), Value int, Liczebnik nvarchar(20), CONSTRAINT PK_RzadValue PRIMARY KEY CLUSTERED (Rzad,Value) ) INSERT INTO Liczebniki VALUES ('J',0,''), ('J',1,' jeden '), ('J',2,' dwa '), ('J',3,' trzy '), ('J',4,' cztery '), ('J',5,' pięć '), ('J',6,' sześć '), ('J',7,' siedem '), ('J',8,' osiem '), ('J',9,' dziewięć '), ('D',0,''), ('D',1,' dziesięć '), ('D',2,' dwadzieścia '), ('D',3,' trzydzieści '), ('D',4,' czterdzieści '), ('D',5,' pięćdziesiąt '), ('D',6,' sześćdziesiąt '), ('D',7,' siedemdziesiąt '), ('D',8,' osiemdziesiąt '), ('D',9,' dziewięćdziesiąt '), ('N',0,' dziesięć '), ('N',1,' jedenaście '), ('N',2,' dwanaście '), ('N',3,' trzynaście '), ('N',4,' czternaście '), ('N',5,' piętnaście '), ('N',6,' szesnaście '), ('N',7,' siedemnaście '), ('N',8,' osiemnaście '), ('N',9,' dziewiętnaście '), ('S',0,''), ('S',1,' sto '), ('S',2,' dwieście'), ('S',3,' trzysta '), ('S',4,' czterysta '), ('S',5,' pięćset '), ('S',6,' sześćset '), ('S',7,' siedemset '), ('S',8,' osiemset '), ('S',9,' dziewięćset '), ('0',1,' tysiąc '),--1 ('0',2,' tysiące '),--2-4,M2-M4 gdzie M>=2 ('0',5,' tysięcy '),--5-21,M5-M9 gdzie M>=2 ('1',1,' milion '), ('1',2,' miliony '), ('1',5,' milionów ')
Trochę dużo tu wartości, ale nic na to nie poradzimy - wartości są unikalne i wynikają wprost ze złożoności naszego języka. Jak można się przekonać, rozpatrujemy wartości rzędu milionów. Przekonamy się wkrótce, że dodanie kolejnych rzędów wielkości nie powinno stanowić problemu. Jak? O tym nieco później.
Parę słów o konstrukcji tabeli. Kolumna Rząd symbolizuje rząd wielkości (tak to sobie nazwałem). J oznacza jedności, D - dziesiątki, N pochodzi od przyrostka -naście, S to setki. Co dalej? Zero oznacza tysiące, jeden miliony (1000 razy większe), 2 mogłoby oznaczać miliardy (1000 razy większe od milionów). Te grupy '1000 razy większe' są już bardziej regularne, dlatego można je umieścić w pętli. Tam mamy do czynienia tylko z trzema formami fleksyjnymi. Aby uprościć algorytm, kolumna Rzad powinna tam mieć zatem kolejne wartości tekstowe, tj. 0, 1, 2 i tak dalej.
Jak wykorzystać tę tabelę?
Sama tabela nic nam jeszcze nie daje. Popatrzmy zatem na funkcję zaprezentowaną na poniższym listingu:
CREATE FUNCTION dbo.KwotaSlownie(@wartosc int) RETURNS nvarchar(200) AS BEGIN IF @wartosc = 0 RETURN 'zero' DECLARE @jednosc int = @wartosc % 10 DECLARE @para int = @wartosc % 100 DECLARE @set int = (@wartosc % 1000) / 100; DECLARE @result nvarchar(200) = '' IF (@para >= 10 AND @para < 20) SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@jednosc) ELSE BEGIN SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10)) + (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc) END SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set) + @result -- X > 1000 DECLARE @mult char(1)='0' SET @wartosc = @wartosc / 1000; WHILE @wartosc>0 BEGIN SET @jednosc = @wartosc % 10; SET @para = @wartosc % 100; SET @set = (@wartosc % 1000) / 100; IF ((@wartosc % 1000) / 10 = 0) BEGIN SET @result = CASE WHEN @jednosc > 1 THEN (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc) ELSE '' END + CASE WHEN @jednosc=1 THEN (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=1) WHEN @jednosc BETWEEN 2 AND 4 THEN (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2) WHEN @wartosc % 1000 != 0 THEN (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5) ELSE '' END + @result END ELSE IF (@para >= 10 AND @para < 20) BEGIN SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@para%10) + (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5) + @result END ELSE BEGIN SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10)) + (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc) + CASE WHEN @jednosc BETWEEN 2 AND 4 THEN (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2) ELSE (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5) END + @result END SET @result = (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set) + @result SET @wartosc = @wartosc / 1000 SET @mult = @mult+1 END RETURN RTRIM(LTRIM(REPLACE(@result,' ', ' '))) END
Trochę dużo tego kodu, ale najważniejsze, że spełnia swoją funkcję. Warto wspomnieć, że poszczególne składniki wyniku otoczone są odstępami - stąd konieczność likwidacji podwójnych spacji w środku tekstu wynikowego oraz pojedynczych na brzegach.
Dużo jest też operacji wyszukiwania w tabeli. Dobra wiadomość jest taka, że tabela jest bardzo mała i operacje fizycznego odczytu nie będą stanowić dużego narzutu - będą to głównie operacje odczytu logicznego, bo strony, z pewnością, zaraz na początku, zostaną umieszczone w pamięci operacyjnej - jeżeli ich tam jeszcze nie było.
Przykład wykorzystania fukcji
Aby przetestować funkcję przygotowałem sobie prosty skrypt. Przyjrzyjmy się zatem, jak to działa:
CREATE TABLE #test ( Kwota int ) DECLARE @i int=0 WHILE @i<10 BEGIN INSERT INTO #test VALUES (ABS(CHECKSUM(NEWID()))%1000000000) SET @i += 1 END SELECT Kwota, dbo.KwotaSlownie(Kwota) Slownie FROM #test DROP TABLE #test
Skrypt generuje 10 losowych wartości i wrzuca je do tabeli tymczasowej. Ma ona reprezentować tabelę produkcyjną. Następnie wybiera wszystkie wartości tabeli tymczasowej i dodaje do nich wartość zwróconą z ledwo co utworzonej, świeżej funkcji dbo.KwotaSlownie. Popatrzmy na przykładowe wyniki:
Kwota | Slownie |
---|---|
630453590 | sześćset trzydzieści milionów czterysta pięćdziesiąt trzy tysiące pięćset dziewięćdziesiąt |
214039041 | dwieście czternaście milionów trzydzieści dziewięć tysięcy czterdzieści jeden |
52009527 | pięćdziesiąt dwa miliony dziewięć tysięcy pięćset dwadzieścia siedem |
156069911 | sto pięćdziesiąt sześć milionów sześćdziesiąt dziewięć tysięcy dziewięćset jedenaście |
430471693 | czterysta trzydzieści milionów czterysta siedemdziesiąt jeden tysięcy sześćset dziewięćdziesiąt trzy |
18756127 | osiemnaście milionów siedemset pięćdziesiąt sześć tysięcy sto dwadzieścia siedem |
570810453 | pięćset siedemdziesiąt milionów osiemset dziesięć tysięcy czterysta pięćdziesiąt trzy |
103920150 | sto trzy miliony dziewięćset dwadzieścia tysięcy sto pięćdziesiąt |
98812148 | dziewięćdziesiąt osiem milionów osiemset dwanaście tysięcy sto czterdzieści osiem |
556772018 | pięćset pięćdziesiąt sześć milionów siedemset siedemdziesiąt dwa tysiące osiemnaście |
Warto wspomnieć, że wyniki na innych komputerach z pewnością będą się różnić - ze względu na funkcję losową.
Ograniczenia - cześć groszowa
Warto wiedzieć, że funkcja nie radzi sobie z wartościami ujemnymi (zwróci NULL) oraz z ułamkami. Co w takim przypadku? Jeżeli są to grosze, to proponuję następujące rozwiązanie:
DECLARE @num decimal(6,2)=3920.50 SELECT dbo.KwotaSlownie(CAST(@num AS int)) [Slownie zl], dbo.KwotaSlownie(CAST(@num*100 AS int)%100) [Slownie gr]
Trik polega na rozdzieleniu części całkowitej od ułamkowej i dwukrotnym wywołaniu funkcji dbo.KwotaSlownie. Rezultat będzie następujący:
Slownie zl | Slownie gr |
---|---|
trzy tysiące dziewięćset dwadzieścia | pięćdziesiąt |
Jak poradzić sobie z liczbą ujemną? Zastosować prosty warunek. Jeżeli liczba jest ujemna to do funkcji należy przekazać wartość bezwzględną, a rezultat uzupełnić słowem 'minus '.
Podsumowanie
Mam nadzieję, że skrypt nie zawiera błędów. Oczywiście nie ponoszę również żadnej odpowiedzialności za szkody spowodowane użyciem powyższego skryptu. Jeżeli gdzieś jest błąd, proszę o ślad w komentarzu, postaram się go poprawić.
Kategoria:SQL Server
Komentarze:
co prawda znaczną część kodu napisałem 'po swojemu', ale sam schemat jak najbardziej dobry!
jeszcze raz, thx!
create or replace function kwota_slownie_f(pp_liczba number) return varchar2 as
--declare
p_liczba number(15,3);
p_minus number(1);
L_J number(1);
L_D number(1);
L_S number(1);
i number(10);
ret varchar2(100);
res varchar2(100);
begin
p_liczba := pp_liczba;
if p_liczba = 0 then
return 'zero';
end if;
if p_liczba <> abs(p_liczba) then
p_minus := 1;
p_liczba := abs(p_liczba);
end if;
if mod(p_liczba,1) <> 0 then
--p_grosze = funkcja(trunc(mod(liczba,1),2)*100)
p_liczba := trunc(p_liczba);
end if;
i:=-1;
res := '';
while p_liczba>0
loop
L_J := mod(p_liczba,10);
L_D := mod(trunc(p_liczba/10),10);
L_S := mod(trunc(p_liczba/100),10);
p_liczba := trunc(p_liczba/1000);
--
if i>=0 then
if L_J=1 and L_S+L_D=0 and i>=0 then
select liczebnik into ret from kwota_slownie where value = 1 and rzad=i||'';
elsif L_J between 2 and 4 and L_D<>1 then
select liczebnik into ret from kwota_slownie where value = 2 and rzad=i||'';
else
select liczebnik into ret from kwota_slownie where value = 5 and rzad=i||'';
end if;
res := trim(ret || ' ' || res);
end if;
--
if L_D = 1 then
select liczebnik into ret from kwota_slownie where value = L_J and rzad='N';
res := trim(ret || ' ' || res);
else
select liczebnik into ret from kwota_slownie where value = L_J and rzad='J';
res := trim(ret || ' ' || res);
select liczebnik into ret from kwota_slownie where value = L_D and rzad='D';
res := trim(ret || ' ' || res);
end if;
if L_S > 0 then
select liczebnik into ret from kwota_slownie where value = L_S and rzad='S';
res := trim(ret || ' ' || res);
end if;
i:=i+1;
end loop;
return replace(trim(res),' ',' ');
end;
/
proponuję dbo.KwotaSlownie(@wartosc bigint) - dziesiątki milionów wylatuja
i w środku także cast na bigint.
A wersja z groszami w postaci n/100:
CREATE FUNCTION dbo.KwotaSlownie(@wartoscwej float)
RETURNS nvarchar(200)
AS
BEGIN
declare @wartosc bigint, @grosze bigint
set @wartosc = cast(@wartoscwej as int)
set @grosze = CAST( (@wartoscwej *100) as bigInt)%100
IF @wartosc = 0
RETURN 'zero'
DECLARE @jednosc int = @wartosc % 10
DECLARE @para int = @wartosc % 100
DECLARE @set int = (@wartosc % 1000) / 100;
DECLARE @result nvarchar(200) = ''
IF (@para >= 10 AND @para < 20)
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@jednosc)
ELSE
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10))
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
END
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set)
+ @result
-- X > 1000
DECLARE @mult char(1)='0'
SET @wartosc = @wartosc / 1000;
WHILE @wartosc>0
BEGIN
SET @jednosc = @wartosc % 10;
SET @para = @wartosc % 100;
SET @set = (@wartosc % 1000) / 100;
IF ((@wartosc % 1000) / 10 = 0)
BEGIN
SET @result =
CASE WHEN @jednosc > 1 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
ELSE ''
END
+ CASE WHEN @jednosc=1 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=1)
WHEN @jednosc BETWEEN 2 AND 4 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2)
WHEN @wartosc % 1000 != 0 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
ELSE ''
END
+ @result
END
ELSE IF (@para >= 10 AND @para < 20)
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@para%10)
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
+ @result
END
ELSE
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10))
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
+ CASE WHEN @jednosc BETWEEN 2 AND 4 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2)
ELSE
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
END
+ @result
END
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set)
+ @result
SET @wartosc = @wartosc / 1000
SET @mult = @mult+1
END
RETURN RTRIM(LTRIM(REPLACE(@result,' ', ' '))) +
' ' + Cast(@grosze as char(2)) + '/100'
END
select ,dbo.GetKwotaSlownie(CAST(kl.BruttoFaktury as int)) +' zł '+ dbo.GetKwotaSlownie(CAST((kl.BruttoFaktury-convert(bigint, kl.BruttoFaktury))*100 as int)%100) +' gr' [BruttoFakturySlownie]
CREATE OR REPLACE FUNCTION MAXIMO.Slownie (IN V_wartosc INT)
RETURNS VARCHAR(200)
LANGUAGE SQL
BEGIN
DECLARE V_jednosc INT;
DECLARE V_para INT;
DECLARE V_set INT ;
DECLARE V_text varchar(200);
DECLARE V_result varchar(200);
-- DECLARE V_mult char(1);
DECLARE V_mult NUMERIC;
SET V_jednosc = MOD(V_wartosc, 10);
SET V_para = MOD(V_wartosc, 100);
SET V_set = MOD(V_wartosc , 1000) / 100;
--SET V_mult='0';
SET V_mult=0;
--SET V_result ='';
IF (V_para >= 10 AND V_para < 20) THEN
SET V_result =(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='N' AND Value = V_jednosc fetch first 1 rows only);
ELSE
SET V_result = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='D' AND Value=(V_para/10) fetch first 1 rows only);
SET V_result = V_result||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='J' AND Value=V_jednosc fetch first 1 rows only);
END IF;
SET V_result = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='S' AND Value=V_set fetch first 1 rows only)||V_result;
WHILE V_wartosc > 0 DO
SET V_jednosc = MOD(V_wartosc, 10);
SET V_para = MOD(V_wartosc, 100);
SET V_set = MOD(V_wartosc , 1000) / 100;
IF MOD(V_wartosc, 1000) / 10 = 0 THEN
IF V_jednosc > 1 THEN
SET V_text = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='J' AND Value=V_jednosc fetch first 1 rows only);
END IF;
IF V_jednosc = 1 THEN
SET V_text = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=1 fetch first 1 rows only);
ELSEIF V_jednosc BETWEEN 2 AND 4 THEN
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=2 fetch first 1 rows only);
ELSEIF MOD(V_wartosc, 1000) != 0 THEN
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=5 fetch first 1 rows only);
END IF;
IF (V_result IS NOT NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text||V_result;
ELSEIF (V_result IS NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text;
ELSE
SET V_result = V_result;
END IF;
ELSEIF (V_para >= 10 AND V_para < 20) THEN
SET V_text = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='N' AND Value=MOD(V_para,10) fetch first 1 rows only);
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=5 fetch first 1 rows only);
IF (V_result IS NOT NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text||V_result;
ELSEIF (V_result IS NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text;
ELSE
SET V_result = V_result;
END IF;
ELSE
SET V_text = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='D' AND Value=(V_para/10) fetch first 1 rows only);
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='J' AND Value=V_jednosc fetch first 1 rows only);
IF V_jednosc BETWEEN 2 AND 4 THEN
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=2 fetch first 1 rows only);
ELSE
SET V_text = V_text||(SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad=TO_CHAR(V_mult) AND Value=5 fetch first 1 rows only);
END IF;
IF (V_result IS NOT NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text||V_result;
ELSEIF (V_result IS NULL AND V_text IS NOT NULL) THEN
SET V_result = V_text;
ELSE
SET V_result = V_result;
END IF;
END IF;
-- SETKI TYSIĘCY
SET V_result = (SELECT Liczebnik FROM MAXIMO.LICZEBNIKI WHERE Rzad='S' AND Value=V_set fetch first 1 rows only)||V_result;
SET V_wartosc = V_wartosc / 1000;
SET V_mult = V_mult + 1;
END WHILE;
RETURN RTRIM(LTRIM(REPLACE(V_result,' ', ' ')));
END
CREATE FUNCTION [dbo].[f_kwota_slownie](@p_wartosc decimal(18,2))
RETURNS nvarchar(200)
AS
BEGIN
declare @wartosc int=cast(@p_wartosc as int)
declare @jednostka varchar(10)='zł'
declare @zdawka varchar(10)='gr'
declare @result nvarchar(200) = ''
IF @wartosc = 0
set @result ='zero'
else
begin
DECLARE @jednosc int = @wartosc % 10
DECLARE @para int = @wartosc % 100
DECLARE @set int = (@wartosc % 1000) / 100;
IF (@para >= 10 AND @para < 20)
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@jednosc)
ELSE
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10))
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
END
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set)
+ @result
-- X > 1000
DECLARE @mult char(1)='0'
SET @wartosc = @wartosc / 1000;
WHILE @wartosc>0
BEGIN
SET @jednosc = @wartosc % 10;
SET @para = @wartosc % 100;
SET @set = (@wartosc % 1000) / 100;
IF ((@wartosc % 1000) / 10 = 0)
BEGIN
SET @result =
CASE WHEN @jednosc > 1 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
ELSE ''
END
+ CASE WHEN @jednosc=1 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=1)
WHEN @jednosc BETWEEN 2 AND 4 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2)
WHEN @wartosc % 1000 != 0 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
ELSE ''
END
+ @result
END
ELSE IF (@para >= 10 AND @para < 20)
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='N' AND Value=@para%10)
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
+ @result
END
ELSE
BEGIN
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='D' AND Value=(@para/10))
+ (SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='J' AND Value=@jednosc)
+ CASE WHEN @jednosc BETWEEN 2 AND 4 THEN
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=2)
ELSE
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad=@mult AND Value=5)
END
+ @result
END
SET @result =
(SELECT TOP 1 Liczebnik FROM Liczebniki WHERE Rzad='S' AND Value=@set)
+ @result
SET @wartosc = @wartosc / 1000
SET @mult = @mult+1
END
end
set @result=@result + ' ' + @jednostka
--fractional part
declare @v_fractional tinyint
set @v_fractional=cast (@p_wartosc % 1 *100 as int)
if @v_fractional=0
set @result=@result+' zero'
else
set @result=@result + ' ' + cast(@v_fractional as varchar)
set @result=@result + ' ' +@zdawka
RETURN RTRIM(LTRIM(REPLACE(@result,' ', ' ')))
END
GO