Rady začátečníkům

Z PostgreSQL
Skočit na navigaci Skočit na vyhledávání

Obecná doporučení a povídání

--Raul 12:59, 10. 4. 2008 (CEST)

Nespoléhejte na různé administrační nástroje

Když mi před pár týdny Pavel Stěhule povídal o pg (pravda, povídal mi o tom už o dost dříve, ale jak se říká zvyk je železná košile, v mém případě zvyk na mysql), řekl mi mezi řečí pár zajímavých bodů :

  1. SQL příkazy piš ručně
  2. piš je do zvlášť souboru a pak na něj v programu odkazuj
  3. nespoléhej na administrační klikátko

Řekl jsem si huh, uff, ghe. Nicméně měl Pavel pravdu a během pár dní jsem zjistil, že velkou pravdu.

  1. různé programy mají různé všelijaké rádoby optimalizace a grafický "Query Builder" např. v EMS pg Manageru si SELECT optimalizují už při vytváření po svém. Velice jsem se divil, kdy po přidání tabulky a vazeb do Query Builderu se výsledný SELECT úplně změnil k nepoznání.
  2. vytvořil jsem si knihovnu, které tento soubor SQL příkazů převede do pascalu, ve kterém programuji, jejímž výsledkem jsou procedury a funkce. Toto jsem navíc udělal zvlášť pro mySQL i pg, tudíž mojí aplikaci moc nezajímá, kterou db zrovna používám.
  3. jak už jsem psal výše, administrační klikátka, mají různé "rádobyfíčurky", někdy pomohou, někdy uškodí. Napadá mě můj pokus o cizí klíč pro zamezení DELETE (ON DELETE RESTRICT), kdy vše po naklikání fungovalo. Až do doby první změny. Z neznámého důvodu totiž EMS pg Manager neumí vytvořit vazbu na cizí klíč pouze pro DELETE, ale zároveň ji vytvoří i pro UPDATE. Ručně napsaný SQL příkaz pro vytvoření tabulky Vám to však neudělá.

Proto doporučuji, když už použít nějaké klikátko, tak jen pro definici kostry na testovacícm schematu a posleze vzit DDL, přečíst, upravit a následně spustit nad skutečným schematem.

Jména objektů v DB

Důležité upozornění pro uživatele přecházející z mySQL na pg je taktéž pojmenovávání objektů v databázi. Zatímco mySQL je case-insensitive a tudíž je jedno jak si kterou tabulku, sloupeček apod pojmenujete, pg má pár zákonitostí, které Vám může připravit pár perných hodin/dní/měsíců/let :-) - (pozn. PostgreSQL je také case-insensitive, až na identifikátory zapsané v uvozovkách, viz dále)

Sice to tady Pavel má, ale raději to zmíním ještě na tomto místě.

Pokud definujete objekt v databázi a jeho jméno v definici uvedete do " je od té chvíle nutnost psát tyto " všude, kde s daným objektem pracujete. Další možností je nepsat " při vytváření těchto objektů, případně si zvyknout na psaní jmen objektů pouze malými písmeny. Bohužel, jak jsem již psal v předchozí části, různá klikátka Vám ty uvozovky v mnoha případech napíšou samy. V mnou používaném EMS pg Lite Manageru jsem asi 4 hodiny hledal, jestli se to nedá nějak vypnout, ale nenašel jsem tuto možnost.

Tipy a triky

Porovnávání řetězců co se podobnosti týče

Narazil jsem na problém, jak poznat zákazníky e-shopu podle jmen (ne vždy zákazník použije svůj login, ale zašle objednávku pod "novým účtem"). Byl jsem upozorněn na trigramy. Copak je to zajímavého ? Jelikož nejsem teoretik, řeknu na rovinu, že do hloubky netuším. Jelikož však samotný trigram mi přijde ne moc šikovný, je dobré nejprve řetězce zbavit balastu, to jest, mezer, českých znaků, a velkých písmen. Zde je výsledná funkce is_similar :

CREATE OR REPLACE FUNCTION "_global_"."is_similar" (ppar1 varchar, ppar2 varchar) RETURNS boolean AS
$body$
DECLARE
  lpar1 varchar;
  lpar2 varchar;
  res boolean;
BEGIN
   res := false;
 
   lpar1 := lower(replace(to_ascii(encode(convert_to(ppar1, 'latin2'),'escape'),'latin2'),' ',''));
   lpar2 := lower(replace(to_ascii(encode(convert_to(ppar2, 'latin2'),'escape'),'latin2'),' ',''));
   IF lpar1=lpar2 THEN
    res := true;
   ELSE
    res := similarity(lpar1,lpar2) >= 0.3;
   END IF;

   IF res IS NULL then
    res := false;
   END IF;

   return res;   
END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY DEFINER;

Pascalisté a funkce v pg

Jako letitý delphista a začínající uživatel databáze pgSQL mám dost často chybu v uložených procedurách. V pgSQL se uložené procedury a funkce píší sice velmi obdobně (což právě může uživatele zmást), nicméně je zde par rozdílů.

Podmínky

Při psaní podmínek IF-THEN-ELSE-END je na rozdíl od pascalu potřeba psát i ; na konci vykonávaných řádků, stejně tak, jako se nevyužívá uvození begin-end.

Pascal:                                                        pg:

  if <podminka> then                                           IF <podminka> THEN 
    prikaz                                                        prikaz;
  else                                                         ELSE
    prikaz;                                                       prikaz;
                                                               END IF;

  if (<podminka>) AND (<podminka>) then                        IF (<podminka>) AND (<podminka>) THEN
  begin                     
     prikaz1;                                                     prikaz1; 
     prikaz2;                                                     prikaz2;
  end else                                                     ELSE
  begin  
    prikaz3;                                                      prikaz3;
    prikaz4;                                                      prikaz4;
  end;                                                         END IF;

Deklarace proměnných

Dalším rozdílem je deklarace proměnných. Zatímco v pascalu máte možnost deklarovat více proměnných stejného typu najednou - oddělené čárkami, v pg tato možnost není a je nutno deklarovat každou proměnnou zvlášť. Taktéž se v pg na rozdíl od pascalu nepoužívá : pro oddělení typu proměnné.

Pascal:                                                        pg:

var prom1, prom2: String;                                      DECLARE prom1 VARCHAR;
    i1: Integer;                                                       prom2 VARCHAR;
                                                                       i1 INTEGER:

Pozor na RETURN

U příkazu RETURN je potřeba dát si pozor na dvě věci :

  1. Na rozdíl od pascalu a jeho proměnné result je RETURN příkazem, který nastaví návratovou hodnotu a UKONČÍ běh funkce.
  2. U funkce nesmí dojít k tomu, že RETURN nebude (z důvodu složitějších podmínek např) proveden.

Osvědčil se mi následující postup :

DECLARE res VARCHAR;
BEGIN
   res := 'nejaka navratova hodnota pro standartni chovani';   

   .... jadro funkce, misto RETURN zde staci nastavit res := 'neco';

   RETURN res;
END;