Spis treści:

Kategoria:SQL Server


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:

KwotaSlownie
630453590sześćset trzydzieści milionów czterysta pięćdziesiąt trzy tysiące pięćset dziewięćdziesiąt
214039041dwieście czternaście milionów trzydzieści dziewięć tysięcy czterdzieści jeden
52009527pięćdziesiąt dwa miliony dziewięć tysięcy pięćset dwadzieścia siedem
156069911sto pięćdziesiąt sześć milionów sześćdziesiąt dziewięć tysięcy dziewięćset jedenaście
430471693czterysta trzydzieści milionów czterysta siedemdziesiąt jeden tysięcy sześćset dziewięćdziesiąt trzy
18756127osiemnaście milionów siedemset pięćdziesiąt sześć tysięcy sto dwadzieścia siedem
570810453pięćset siedemdziesiąt milionów osiemset dziesięć tysięcy czterysta pięćdziesiąt trzy
103920150sto trzy miliony dziewięćset dwadzieścia tysięcy sto pięćdziesiąt
98812148dziewięćdziesiąt osiem milionów osiemset dwanaście tysięcy sto czterdzieści osiem
556772018pięć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 zlSlownie gr
trzy tysiące dziewięćset dwadzieściapięć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

, 2013-12-20

Komentarze:

Scot Harvath (2014-08-07 17:24:34)
dzięki! przydało się

co prawda znaczną część kodu napisałem 'po swojemu', ale sam schemat jak najbardziej dobry!

jeszcze raz, thx!
Marecki (2015-04-27 17:34:08)
Dla przyszłych pokoleń przepisałem na szybko na oracle. Może się komuś przyda kiedyś.

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;
/
wedrowycz (2016-02-15 13:51:27)
Dzieki powyższym.
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
MilesDavis (2016-10-26 11:51:45)
Uzycie z groszami:

select ,dbo.GetKwotaSlownie(CAST(kl.BruttoFaktury as int)) +' zł '+ dbo.GetKwotaSlownie(CAST((kl.BruttoFaktury-convert(bigint, kl.BruttoFaktury))*100 as int)%100) +' gr' [BruttoFakturySlownie]
miro (2017-06-07 20:00:26)
To wersja dla środowiska DB2:

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;
miro (2017-06-07 20:01:02)
SET V_wartosc = V_wartosc / 1000;
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
blazek (2018-05-06 21:25:49)
wersja z jednostkami zł i gr



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


Dodaj komentarz
Wyślij
Ostatnie komentarze
Dzieki za rozjasnienie zagadnienia upsert. wlasnie sie ucze programowania :).
Co się stanie gdy spróbuję wyszukać:
SELECT * FROM NV_Airport WHERE Code='SVO'
SELECT * FROM V_Airport WHERE Code=N'SVO'
(odwrotnie są te N-ki)
Będzie konwersja czy nie znajdzie żadnego rekordu?