Vytváření uživatelských funkcí

O vytvárení funkcí by se mohla napsat samostatná kniha, neboť se v něm, krom jiného, využívá programování. Nechci se pouštět do vysvětování programování (od toho tu jsou jiné tutoriály), proto uvedu jen pár jednoduchých příkladů vytvoření funkce a pokud vás to zaujme, můžete si zbytek dostudovat z oficiální dokumentace.

Toto je (prozatím?) poslední kapitola, takže vám přeji hodně zábavy při využívání všech vašich nabytých znalostí.

CREATE FUNCTION

Funkce (přesněji user defined functions) se v PostgreSQL vytvářejí příkazem CREATE FUNCTION.

Zjednodušená syntaxe příkazu je následující:

CREATE [OR REPLACE] FUNCTION jmeno_funkce ([typ_argumentu [, ]])
        RETURNS typ_navratove_hodnoty
        AS 'definice funkce'
        LANGUAGE jmeno_jazyka;

Příkazem CREATE FUNCTION jmeno_funkce vytvoříte funkci jen v případě, že funkce tohoto jména ještě neexistuje.
Pokud použijete příkaz CREATE OR REPLACE FUNCTION jmeno_funkce, bude existující funkce stejného jména přepsána. (Přepsat můžete jenom funkce vytvořené pomocí CREATE FUNCTION, ne standardní funkce postgresu).

K čemu slouží jmeno_funkce je snad jasné. Argument (nebo argumenty) funkce se předávají při použití funkce v závorce, oddělené čárkou. Během deklarace funkce musíte určit typ_argumentu. (Například real, string atp.) Funkce nemusí mít žádné argumenty, pak se při deklaraci a použití funkce musí použít prázdné závorky.

Za závorkami následuje klíčové slovo RETURNS a typ návratové hodnoty funkce (real, string atp.). K tomu, k čemu je návratová hodnota, se ještě dostanu (programátoři jistě vědí).

Za klíčovým slovem AS je uvedeno tělo funkce. Tělo funkce je v podstatě popis činnosti, kterou má funkce vykonávat. Jak takový popis činosti vypadá, záleží na programovacím jazyku, který k popisu činosti použijete. (V PostgreSQL máte více možností).
Tělo funkce se zadává jako string (fakt, nekecám, taky mě to překvapilo), proto musí být uzavřené v apostrofech (nebo do čeho se text dá uzavřít).

Za klíčovým slovem LANGUAGE je název jazyka, který byl použit pro definici těla funkce. Asi vás už napadlo, že je tomu tak proto, že těch jazyků je více. Například 'internal', C, SQL, PL/pgSQL a další. Běžný uživatel má k dispozici jazyk SQL popsaný níže.

Funkce lze přetěžovat. To znamená, že je možné vytvořit více funkcí stejného jména, které se ovšem liší počtem a/nebo typem argumentů.

DROP FUNCTION

Protože je možné funkce přetěžovat, musí se příkazu DROP FUNCTION předat nejen název funkce, ale i typy argumentů, aby podle nich mohl jednoznačně identifkovat správnou verzi funkce ke smazání.

DROP FUNCTION jmeno_funkce ([typ_argumentu [, typ_argumentu, ...]]);

Samozřejmě můžete odstranit funkci jen pokud na to máte práva.
Můžete mazat jen uživatelské funkce (user defined functions), tedy funkce vytvořené pomocí CREATE FUNCTION, nikoliv interní funkce Postgresu.
Smaže se ta funkce zadaného jména, která má shodný počet a typ argumetnů.

Jazyk SQL

Začnu příkladem. Vytvořím funkci pomocí jazyka SQL. To znamená, že za klíčovým slovem LANGUAGE bude jazyk SQL a tělo funkce za klíčovým slovem AS se bude skládat jen z příkazů SQL. To je asi ten nejjednodušší způsob, jak napsat funkci :-).

Návratovou hodnotou (RETURN) funkce jazyka SQL je výsledek posledního SQL příkazu.

Funkce, kterou vytvořím, bude pouze vracet součet dvou čísel typu integer (Tedy návratová hodnota bude typu integer a argumenty funkce budou dvě čísla typu integer).

rimmer1=> CREATE FUNCTION soucet (integer, integer)
RETURNS integer
AS '
        SELECT $1 + $2;
'

LANGUAGE SQL;

V příkladu si všiměte, jak se argumenty v tělu funkce používají. První argument je označen $1, druhý $2 atd.

Návratovou hodnotou je výsledek posledního (v příkladu jediného) SELECTu.

rimmer1=> SELECT soucet(1,1);
 soucet
--------
      2
(1 řádka)

Další ukázka je převzata z dokumentace PostgreSQL. Všiměte si, že místo apostrofů je tělo funkce uzavřeno v $$. (To je v PostgreSQL další způsob, jak je možné ohraničovat text). To je preferovaný způsob, protože umožňuje v tělu funkce používat apostrofy bez nutnosti jejich escapování (pomocí zpětného lomítka).

CREATE FUNCTION tp1 (integer, numeric) RETURNS numeric AS $$
    UPDATE bank
        SET balance = balance - $2
        WHERE accountno = $1;
    SELECT balance FROM bank WHERE accountno = $1;
$$ LANGUAGE SQL;

Funkci se vám nepodaří vytvořit, pokud neexistuje tabulka bank. (Například CREATE TABLE bank (accountno INT, balance NUMERIC);)

Další informace o jazyku SQL najdete v dokumentaci.

Přetěžování funkcí

Funkci soucet z předchozího příkladu přetížím.

O funkci se říká že je přetížená, pokud existuje více funkcí stejného jména, které se odlišují počtem nebo typem argumentů. V příkladu se budou lišit typem argumentů.

Změna typu návratové hodnoty pro přetížení funkce nestačí. Při volání funkce je jasné, kolik a jakého typu jsou argumenty, ale návratová hodnota se z volání funkce odvodit nedá. Takže by se ani nedalo vybrat správnou verzi funkce.

rimmer1=> CREATE FUNCTION soucet (float, integer)
RETURNS float
AS '
SELECT $1 + $2;'

LANGUAGE 'sql';

Funkce se mohou volat následovně:

rimmer1=> SELECT soucet (3,-1),soucet (3.4,-1),soucet(-1,3.4);
 soucet | soucet | soucet
--------+--------+--------
      2 |    2.4 |      2
(1 row)

V prvním případě byla volána funkce soucet(integer,integer) ve druhém případě soucet(float, integer).

Protože není definovaná funkce soucet(integer,float), byla v třetím případě použita funkce soucet(integer, integer) a číslo typu float (3.4) bylo Postgresem převedeno na typ integer (3).
Někdy by podobné automatické konverze mohli být nebezpečné, proto je třeba si na to dávat pozor.

UPDATE: Nově se teď v Postgresu třetí volání (s nesprávnými datovými typy) vyvolá chyba. Argumenty musíte explicitně přetypovat:

rimmer1=> SELECT soucet(-1, CAST(3.4 AS INTEGER));
 soucet
--------
      2
(1 řádka)

Přetěžování funkcí funguje stejně i v dalších jazycích (PL/pgSQL atd.).

Funkce můžete vypsat pomocí metapříkazu \df.

Jazyk PL/pgSQL

Jazyk SQL je omezený pouze na SQL příkazy (SELECT,UPDATE, DELETE atp.).
Jazyk PL/pgSQL naproti tomu umí takové věci, jako deklaraci proměnných, cykly, podmínky, odchytávání výjimek.

Pokud se někdy rozhodnete napsat malinko složitější funkci, pravděpodobně sáhnete pro jazyku PL/pgSQL.

Struktura těla funkce v jazyku PL/pgSQL vypadá takto:

[ <<?php ?><label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
END [ label ];

V části DECLARE se deklarují proměnné, mezi BEGIN a END je pak program. (BEGIN/END v tomto případě nemají nic společného s transakcemi). label je libovolný název bloku, který můžete použít pro kvalifikaci proměnných pomcí tečkové notace.

CREATE FUNCTION suma(int[]) RETURNS int AS $$
DECLARE
  s int := 0;
  x int;
BEGIN
  FOREACH x IN ARRAY $1 LOOP
    s := s + x;
  END LOOP;
  RETURN s;
END;
$$ LANGUAGE plpgsql;
rimmer1=>  SELECT suma('{3,3,5}');
-- nebo lépe SELECT suma(CAST('{3,3,5}' AS integer[]));
 suma
------
   11
(1 řádka)

Jazyk PL/Python

S pl/pgSQL byste si měli vystačit, ale někdy narazíte na to, že je to velice jednoduchý programovací jazyk a vám by se hodil nějaký komplexnější. K tomu můžete využít například perl, nebo python.

Abyste mohli použít jazyk PL/Python, musíte si ho nejdřív pro danou databázi „aktivovat“ příkazem CREATE EXTENSION. (Musíte na to taky mít příslušná práva).

rimmer1=# CREATE EXTENSION plpythonu;
ERROR:  could not open extension control file "/usr/share/postgresql92/extension/plpythonu.control": Adresář nebo soubor
neexistuje

Tohle na mě vyzkočilo, když jsem to zkoušel v OpenSUSE. Extension plpythyonu neexistovala, musel jsem si jí extra doinstalovat:

root# sudo zypper install postgresql-plpython

Teď už to šlo (pod superuživatelským účtem postgres):

-- jako uživatel postgres
rimmer1=# CREATE EXTENSION plpythonu;
CREATE EXTENSION

Metapříkazem \dL si můžete nechat vypsat aktivní jazyky:

rimmer1=> \dL
                                 Seznam jazyků
   Jméno   | Vlastník | Důvěryhodný |                  Popis                  
-----------+----------+-------------+------------------------------------------
 plpgsql   | postgres | t           | PL/pgSQL procedural language
 plpythonu | postgres | f           | PL/PythonU untrusted procedural language
(2 řádky)

Jazyk plpythonu je označen jako nedůvěryhodný, takže jej běžný uživatel nemůže používat. Buď musí míst superuživatelská práva, nebo musíte změnit důveryhodnost jazyka na true.

CREATE FUNCTION pymax (a integer, b integer)
  RETURNS integer
AS $$
  if a > b:
    return a
  return b
$$ LANGUAGE plpythonu;

ERROR:  permission denied for language plpythonu

Jako nedůvěryhodný je plpythonu označen proto, protože s ním může nekalý uživatel narušit běh serveru (například jeho vytížením). Když vím, že uživatelé mého serveru jsou důvěryhodní, změním plpythonu na důvěryhodný:

-- jako uživatel postgres
rimmer1=> SELECT * FROM pg_language WHERE lanname= 'plpythonu';
  lanname  | lanowner | lanispl | lanpltrusted | lanplcallfoid | laninline | lanvalidator | lanacl
-----------+----------+---------+--------------+---------------+-----------+--------------+--------
 plpythonu |       10 | t       | f            |         74544 |     74545 |        74546 |
(1 řádka)
rimmer1=# UPDATE pg_language SET lanpltrusted = true WHERE lanname = 'plpythonu';
UPDATE 1
-- ted muze pouzivat python kazdy

Jinou možností by bylo nastavit jen konkrétnímu uživateli superuživatelská práva:

-- jako uživatel postgres
rimmer1=# ALTER USER petr WITH superuser;
ALTER ROLE
-- ted je petr superuser

Příkaz DO umožňuje spustit tělo funkce, bez toho, aby se musela funkce definovat. Toho se dá využít pro ověření funkčnosti jazyka:

rimmer1=> DO $$
import sys
plpy.info (sys.version_info); return None
$$ LANGUAGE plpythonu;
INFO:  sys.version_info(major=2, minor=7, micro=8, releaselevel='final', serial=0)
KONTEXT:  PL/Python anonymní blok kódu
DO
Modul plpy je vždy automaticky importovaný. Obsahuje užitečné metody jako je info, která zobrazí INFO hlášení (klasické pythonovské metody pro výpis, jako je print, nemůžete použít).

MySQL

V MySQL neexistují „jazyky“. Máte k dispozici jen jeden „jazyk“, který můžete používat s CREATE FUNCTION pro tělo funkce. Nejvíce se podobá postgresovskému jazyku SQL – prostě jen spouštíte SQL příkazy. MySQL má ve svých SQL příkazech i různé řídící konstrukce (IF, LOOP, WHILE, RETURN) atp., které můžete používat ve funkcích a procedůrách, takže se psaní funkcí vlastně více podobá jazyku pl/pgSQL.

MySQL má kromě CREATE FUNCTION ještě CREATE PROCEDURE.
Procedůra se volá pomocí CALL nazvev_procedury(); a nemá návratovou hodnotu (může vracet hodnoty pomocí výstupních parametrů, ale to je nad rámec této kapitoly :-).

Funkce naproti tomu mohou vracet hodnotu, mohou být volány jako jakékoliv jiné funkce MySQL v SQL příkazech.

V MySQL jsou výstupem procedury všechny výstupy ze SELECTů spuštěných v těle procedury (ne jen ten poslední, jako v Postgresu). Né každý klient se s tím dokáže poprat, takže se takovým opičárnám raději vyhněte.
Funkce vracejí hodnotu pomocí klíčového slova RETURN.

V MySQL se nepíše tělo funkce jako textový řetězec, takže je trochu problém s ukončováním SQL příkazů v těle versus ukončení definice funkce. Obvykle totiž klient (program mysql), když narazí na středník, pošle příkaz serveru. To by způsobilo odeslání začátku funkce a prvního příkazu v těle funkce ukončeného středníkem. Zbytek funkce (resp. další příkazy v těle funkce ukončené středníkem) by se posílaly na server jako další nesouvisející příkazy. Tak tak to prostě nejde.

Obejít se to dá změnou ukončovače (DELIMITER) ze středníku na něco jiného. Obyvkle se používají lomítka //.

Argumenty funkce/procedury musí mít jména (v PostgreSQL mohou a nemusí).

mysql> DELIMITER //
mysql> CREATE FUNCTION soucet (p1 integer, p2 integer)
RETURNS integer
DETERMINISTIC
BEGIN
    RETURN p1 + p2;
END
//
mysql> DELIMITER ;

Klíčové slovo DETERMINISTIC říká, že funkce pro stejné argumenty vrací vždy stejný výsledek. Další možností je NO DETERMINISTIC. (Tato informace je důležitá pro optimalizaci dotazů.)

MySQL nepodporuje konstrukci CREATE OR REPLACE FUNCTION;. (Místo toho umí DROP FUNCTION IF EXISTS.)

V MySQL není možné funkce přetěžovat. Proto se při mazání funkce nemusí uvádět parametry.

mysql> SELECT soucet(3,-4);
+--------------+
| soucet(3,-4) |
+--------------+
|           -1 |
+--------------+
1 row in set (0.00 sec)
mysql> DROP FUNCTION soucet;
Query OK, 0 rows affected (0.04 sec)

Ještě ukázka vytvoření, použití a smazání procedury:

mysql> DELIMITER //
mysql> CREATE PROCEDURE soucet (p1 integer, p2 integer)
DETERMINISTIC
BEGIN
    SELECT p1 + p2;
END
//
mysql> DELIMITER ;
myqsl> CALL soucet(3,-4);
+---------+
| p1 + p2 |
+---------+
|      -1 |
+---------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> DROP PROCEDURE IF EXISTS soucet;
Query OK, 0 rows affected (0.00 sec)

SQLite

V SQLite nelze vytvořit uživatelské funkce pomocí CREATE FUNCTION. Můžete si jen doprogramovat funkce pomocí jazyka C, ale to už je nad rámec tohoto tutoriálu.

Oracle

Jazyk pl/pgSQL vychází z Oracle jazyka PL/SQL. Z toho vyplývá, že vytváření funkcí v Oracle je hodně podobné. Můžete se podívat do dokumentace PostgreSQL na Porting from Oracle PL/SQL, kde jsou popsány základní rozdíly mezi pl/pgSQL a PL/SQL.

Nějaké to programování v Oracle si můžete prohlédnout v kapitole o triggerech.

Teď jen ve stručnosti ukáži, jak by se daly v Oracle řešit příklady popsané v předchozí části o PostgreSQL. Začnu funkcí soucet.

Místo AS se píše v Oracle IS, místo RETURNS je před IS RETURN, tělo se nezadává jako text, argumenty mají jméno (i a j) a na konci se neurčuje použitý programovací jazyk, protože v Oracle je jen jeden – PL/SQL.

Postgres taky umožňuje argumenty funkce pojmenovat. Přečtěte si dokumentaci :-).

Použití:

oracle> SELECT soucet(1,1) FROM dual;

SOUCET(1,1)
-----------
          2
 

Funkce a procedury

Začněme přípravou tabulky a ukázkou funkce tp1:

CREATE TABLE bank(balance numeric, accountno integer);
INSERT INTO bank VALUES(1000,1);

CREATE OR REPLACE FUNCTION tp1 (a integer, b numeric)
RETURN numeric
IS
 r numeric;
 BEGIN
     UPDATE bank SET balance = balance - b
        WHERE accountno = a;
     SELECT balance
        INTO r
        FROM bank WHERE accountno = a;
     RETURN r;
END;
/

Pokus o použití:

oracle> SELECT tp1(1,600) FROM DUAL;
ORA-14551: cannot perform a DML operation inside a query

Oracle nepovoluje spouštět DML (Data modification language) příkazy ve funkcích, tedy v našem případě UPDATE, uvnitř jiného SQL dotazu. Je to něco kvůli transakcím, ale ono obecně je to blbý nápad mít funkci s „side efektem“. Obejít se to dá tak, že funkci zavoláte následujícím způsobem:

oracle> SET SERVEROUTPUT ON
oracle> DECLARE
 r numeric;
BEGIN
  r:=tp1(1,600);
  DBMS_OUTPUT.put_line (r);
END;
/
400

Funkce put_line z balíčku DBMS_OUTPUT vypíše svůj argument na obrazovku. Tedy v případě, že je nastaven SERVEROUTPUT na ON.

Pokud chcete používat DML, většinou se na to v Oracle PL/SQL používají procedury. Procedura je to samé jako funkce, jenom nemá návratovou hodnotu a volá se pomocí EXEC (ne SELECTem).

CREATE OR REPLACE PROCEDURE tp2 (a integer, b numeric)
IS
BEGIN
     UPDATE bank SET balance = balance - b
        WHERE accountno = a;
END;
/

Spuštění procedury pomocí EXEC:

oracle> SELECT * FROM bank;
   BALANCE  ACCOUNTNO
---------- ----------
       400          1

oracle> EXEC tp2(1,200);
PL/SQL procedure successfully completed.

oracle> SELECT * FROM bank;
   BALANCE  ACCOUNTNO
---------- ----------
       200          1

Mnohem hezčí, že? :-) Dokonce můžete místo EXEC použít CALL, jako v MySQL.

Pole

Pokud jde o práci s polem, v Oracle je potřeba si nejdřív definovat vlastní typ. Následující příklad vytvoří datový typ se jménem intArrayTyp, který bude obsahovat 200 hodnot typu integer.

CREATE OR REPLACE TYPE intArrayTyp AS VARRAY(200) OF integer;
/

Datový typ lze smazat příkazem DROP TYPE jmeno_typu;

LOOP se používá v Oracle trochu jinak než v Postgresu, jinak je funkce suma hodně podobná:

CREATE OR REPLACE FUNCTION suma(a intArrayTyp)
RETURN integer
IS
  s integer := 0;
  i integer;
BEGIN
FOR i IN 1..a.count LOOP
    s := s + a(i);
    END LOOP;
RETURN s;
END;
/

S použitím už je to horší. V příkladu vidíte, jak se v oracle vytvoří typ (řádka 4), nastaví se, kolik může obsahovat hodnot (řádka 5) a pak se pole hodnotami naplní (řádky 6 a 7).

Pokud byste vynechali volání na řádce 5, nebo mu zkusili dát čílo větší než našich deklarovaných 200 položek, dojde k chybě.

  1. v_t intArrayTyp;
  2. v_t := intArrayTyp();
  3. v_t.extend(2);
  4. v_t(1) := 1;
  5. v_t(2) := 3;
  6. DBMS_OUTPUT.put_line (suma(v_t));
  7. /

Na výstup se vypíše 4.

Balíčky

Balíčky (packages) jsou databázové objekty, které seskupují funkce, procedury, typy, proměnné atp. Můžete si je představit jako třeba struktury v jazyku C, nebo record v Pascalu. V Postgresu balíčky neexistují, místo nich se doporučuje používat schema.

Důvod, proč se tu o balíčcích zmiňuji je hlavně ten, že v Oracle je možné přetěžovat (overload) funkce jen v nich.

Kromě balíčků, které si naprogramujete sami, existují balíčky, které jsou součástí Oracle od jeho instalace. S jedním z nich už jste se setkali – s balíčekem DBMS_OUTPUT, který obsahuje funkci put_line (a spousty dalších).

Dalším takovým balíčkem je balíček STANDARD. Ten má tu zvláštnost, že když chcete zavolat jeho funkce, nemusíte je kvalifikovat jeho jménem. Takže například volání STANDARD.ABS(-5) lze zapat jako ABS(-5).

Všechny objekty z balíčku STANDARD můžete vypsat takto:

oracle> SELECT procedure_name
 FROM SYS.all_procedures
  WHERE object_name = 'STANDARD' AND procedure_name NOT LIKE '%SYS$%'
  ORDER BY procedure_name;

PROCEDURE_NAME
------------------------------
ABS
ABS
ABS
ABS
ACOS
ACOS
ADD_MONTHS
ADD_MONTHS
ASCII
...
383 rows selected.

Všiměte si, že funkce ABS je tam několikrát. To právě kvůli tomu, že je přetížená (existuje více verzí s různým počtem a druhem argumentů).

Kvůli optimalizaci rozděluje Oracle vytvoření balíčku do dvou kroků. V prvním se deklaruje, co balíček obsahuje. Deklaruji tedy balíček matika se dvěmi verzemi funkce soucet.

CREATE OR REPLACE PACKAGE matika AS
   FUNCTION soucet (a integer,b integer) RETURN integer;
   FUNCTION soucet (a float, b integer) RETURN float;
end;
/

V druhém kroku definuji těla funkcí (BODY).

CREATE OR REPLACE PACKAGE BODY matika AS
function soucet (a integer,b integer) return integer
is
begin
        return a + b;
end;
function soucet (a float, b integer) return float
is
begin
        return a + b;
end;

END;
/

Hurá. Teď už je jen použít:

oracle> SELECT soucet (3,-1),soucet (3.4,-1),soucet(-1,3.4) FROM dual;

SOUCET(3,-1) SOUCET(3.4,-1) SOUCET(-1,3.4)
------------ -------------- --------------
           2              2              2

Aha, tak to nevyšlo. Jen jsem 3x zavolal funkci soucet, kterou jsem definoval dříve bez balíčku. Nesmí se zapomenout na kvalifikaci názvem balíčku.

oracle> SELECT matika.soucet (3,-1),matika.soucet (3.4,-1),matika.soucet(-1,3.4) FROM dual;
SELECT matika.soucet (3,-1),matika.soucet (3.4,-1),matika.soucet(-1,3.4) FROM dual
                                                   *
ERROR at line 1:
ORA-06553: PLS-307: too many declarations of 'SOUCET' match this call

Tak bohužel, tohle v Oracle nepůjde. Oracle nedokáže rozlišit float od integeru. Přestože dovolil vytvořit funkce, které se od sebe lišily jen v těchto typech parametrů. No, ale abyste mi věřili, že se funkce dají přetěžovat, ukáži příklad s typem varchar2 místo float. Ten už snad od integer odliší.

DROP PACKAGE matika;
CREATE OR REPLACE PACKAGE matika AS
   function soucet (a integer,b integer) return integer;
   function soucet (a varchar2, b integer) return number;
end;
/

CREATE OR REPLACE PACKAGE BODY matika AS
function soucet (a integer,b integer) return integer
is
begin
        RETURN a + b;
end;
function soucet (a varchar2, b integer) return number
is
begin
        RETURN TO_NUMBER(a) + b;
end;
END;
/

Chvilka napětí, jak to dopadne:

oracle> SELECT matika.soucet (3,-1),matika.soucet (3.4,-1),matika.soucet(-1,3.4) FROM dual;
MATIKA.SOUCET(3,-1) MATIKA.SOUCET(3.4,-1) MATIKA.SOUCET(-1,3.4)
------------------- --------------------- ---------------------
                  2                     2                     2

První pokus ve všech příkladech volal verzi funkce s objema parametry typu integer. Teď zkusím při druhém volání předat jako první parametr text. Nejdřív ale pro jistotu nastavím oddělovače desetinných míst a tisíců, aby náhodou Oracle neočekával číslo v českém formátu (tedy s desetinnou čárkou, místo tečky).

První příkaz z příkladu nastavuje jako oddělovač desetin tečku a jako oddělovač tisíců čárku. Je to podbné, jako nastavování NLS_DATE_LANGUAGE při konverzi data. Tentokrát jsem ale použil nastavení pro celé sezení, nejen pro volání konverzní funkce.

oracle> ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ".,";
Session altered.

oracle> SELECT matika.soucet (3,-1),matika.soucet ('3.4',-1),matika.soucet(-1,3.4) FROM dual;
MATIKA.SOUCET(3,-1) MATIKA.SOUCET('3.4',-1) MATIKA.SOUCET(-1,3.4)
------------------- ----------------------- ---------------------
                  2                     2.4                     2

No vida, toto už vyšlo. Ale neradujte se předčasně.

oracle> SELECT matika.soucet (3,'-1') FROM dual;
ORA-06553: PLS-307: too many declarations of 'SOUCET' match this call

V tomto posledním příkladu si Oracle zase neporadil. Člověk by čekal, že překonvertuje '-1' na integer (jako to udělal v třetím volání v předchozím příkladě s floatem), ale tentokrát se mu to nějak nelíbí.

Rozdíly mezi Postgresem a Oraclem jsou na první pohled malé, ale někdy mohou být velmi zapeklité. V této kapitole jsem vám ukázal něco málo z možností programování. Pokud vás toto téma zaujalo (a já doufám že ano), nastudujte si zbytek z dokumentace, je toho ještě hodně zajímavého, co můžete objevit :-).

Komentář Hlášení chyby
Created: 11.9.2005
Last updated: 24.9.2015
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..