PostgreSQL SQL

Allikas: Kuutõrvaja
Redaktsioon seisuga 28. märts 2010, kell 02:01 kasutajalt Imre (arutelu | kaastöö) (Tehted ajaga)

Sissejuhatus

TODO

Andmebaasi klientprogramm

Reeglina sisaldab andmebaasitarkvara lisaks andmebaasi serverile ka mingit terminalil kasutatavat nö käsurea klientprogrammi, nt PostgreSQL puhul on selleks programm psql.

  • andmebaasi kliendi kasutamine kalkulaatorina
select (5 * 5);
 ?column? 
----------
       25
(1 row)
  • andmebaasi klient töötab sõnedega
select 'Hello' || ' World!';
   ?column?   
--------------
 Hello World!
(1 row)
  • Andmebaasi kliendi juures saab määrata esituse formaati, nt (vaikimisi on see aligned)
\pset format html

Select

select lausega saab lihtsamal juhul kasutada andmebaasis kirjeldatud funktsioone, nt

select sqrt(25);

Tabli moodustamine select lause väljundist

select * into pgcrypto.priidutabel from priit.priidutabel;

Tehted hulkadega

UNION, INTERSECT JA EXECPT abil on võimalik kombineerida mitut select lauset kusjuures

  • UNION - esitatakse read, mis on ühes või mõlemas result setis
  • INTERSECT - esitatakse read, mis on mõlemas result setis
  • EXECPT - esitatakse read, mis on esimeses kuid mitte teises result setis

Näiteks

select nimi from hulgad.hulk1 except select nimi from hulgad.hulk2;

Andmebaasi hierarhia

  • andmekluster
  • andmebaas
create database andmebaasinimi;
  • skeem
create schema skeeminimi;
  • tabel
create table ...

Andmetüübid

http://www.postgresql.org/docs/current/interactive/datatype.html

Numbrilised tüübid

  • integer - 4 baiti pikk täisarv, omandab väärtusi vahemikus -2147483648 kuni +2147483647
  • serial - automaatselt suurenev täisarv, omandab väärtusi vahemikus 1 kuni 2147483647

Character tüübid

  • varchar(n), character varying(n) - vahemikus 0 - n muutuva suurusega string
  • char(n) - täpselt pikkusega n string
  • text - piiramatu pikkusega string

Date/Time tüübid

Viivituse esilekutsumiseks sobib kasutada, kus 2 tähendab kahte sekundit

select pg_sleep(2);

Tõeväärtuse tüübid

TODO

Võrguaadressi tüübid

  • inet -

Massiivi tüübid

TODO

Loendur

Loenduri (ingl. k. sequence) käest saab küsida järjestikulisi väärtusi, vaikimisi need väärtused kasvavad alatest ühest ühe kaupa.

Loenduri moodustamiseks sobib öelda

CREATE SEQUENCE loendurinimi start 1;

ja loenduri käest saab küsida järgmist väärtust

SELECT nextval('loendurinimi');

Praktiliselt kasutatakse loendureid mõne tabeli unikaalsete automaatselt kasvavate väärtustega attribuudina. Nt moodustades tabeli selliselt

CREATE TABLE mart.inimene
(
  inimene_id serial NOT NULL,
  nimi character varying(50),
  vanus integer,
  CONSTRAINT inimene_id_pkey PRIMARY KEY (inimene_id)
)

tekitatakse automaatselt loendur inimene_inimene_id_seq

CREATE SEQUENCE mart.inimene_inimene_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 5
  CACHE 1;

Relatsioonid

TODO

Tabel

Ajutine tabel eksisteerib kuni andmebaasiühenduse lõpuni

CREATE TEMP TABLE tabelinimi(name varchar(50), vanus integer)

Mõisted

  • result set - vastus andmebaasile esitatud päringule, või sisaldada mitte midagi, ühte või enamat rida

Misc laused

  • tabel ühte tehtud päringu tulemuste lisamine tabel kahte
insert into tabel2 (nimi, aadress) select nimi, aadress from tabel1
  • Andmete kopeerimine failisüsteemi
copy customers to '/tmp/customers.txt';
  • Andmete kopeerimine failisüsteemist
copy customers from '/tmp/customers.txt';

Primaarne võti

Primaarse võtmega (ingl. k. primary key) tabeli moodustamine

CREATE TABLE tabelinimi (
  id          SERIAL PRIMARY KEY,
  title       CHARACTER VARYING(80)
);

Olemasolevale tabelile võtme lisamine

ALTER TABLE tabelinimi ADD PRIMARY KEY (valjanimi_id);

Välisvõti

Välisvõtme (ingl. k. foreign key) kasutamiseks sobib moodustada tabel selliselt

CREATE TABLE rentals (
  tape_id     CHARACTER(8) REFERENCES tapes,
  customer_id INTEGER      REFERENCES customers,
  rental_date DATE
);

enesele viitav välisvõti

Enesele viitav välisvõti (ingl. k self-refrencing foreign key) viitab sama tabeli mõnele unikaalsele väljale, nt

CREATE TABLE vanemadjalapsed
(
  inimesenimi character varying(50) NOT NULL,
  lapsenimi character varying(50),
  vanemanimi character varying(50),
  CONSTRAINT vanemajalapsed_pkey PRIMARY KEY (inimesenimi),
  CONSTRAINT vanemadjalapsed_fk FOREIGN KEY (vanemanimi)
     REFERENCES vanemadjalapsed (inimesenimi) MATCH SIMPLE
     ON UPDATE CASCADE ON DELETE NO ACTION
)

kus

  • inimesenimi - ...
  • lapsenimi - ...
  • vanemanimi - ...
  • on update cascade - tagab, et kui mõni inimesenimi väärtus muutub, siis muutub ka vastava nime kasutus kõigis vanemanimi lahtrites kus seda on kasutatud

Indeksid

TODO

Vaated

TODO

Reeglid

Reeglid (ingl. k. rules) http://www.postgresql.org/docs/current/static/rules.html võimaldavad muuta päringuid enne nende päringu plaanija (ingl. k. query planner) juurde jõudmist ja päringute täitmist.

Nt eeldusel, et skeemis reeglid on olemas tabelid essa ja tessa võiks selline reegel kõik insert sisestused sooritada tabelisse tessa juhul, kui nimi väärtuseks on 'Mart'

CREATE RULE sisesta_tessasse AS
ON INSERT TO reeglid.essa WHERE nimi = 'mart'
DO INSTEAD
   INSERT INTO reeglid.tessa values (new.*);

Transaktsioon

TODO

Jõudlus

explain verbose select * from teenused where nimi='teenuse nimi_O_13437';
                                 QUERY PLAN                                 
----------------------------------------------------------------------------
 Bitmap Heap Scan on teenused2  (cost=6.60..196.17 rows=48 width=48)
   Output: id, nimi, aadress
   Recheck Cond: ((nimi)::text = 'teenuse nimi_O_13437'::text)
   ->  Bitmap Index Scan on teenused_idx  (cost=0.00..6.59 rows=48 width=0)
         Index Cond: ((nimi)::text = 'teenuse nimi_O_13437'::text)

Päästik

Päästikuks (ingl. k. trigger) nimetatakse sellist funktsiooni, mille täitmine kaasneb automaatselt vastavas tabelis toimuva muudatusega. Nt olgu olemas tabel customers

CREATE TABLE customers 
(
  customer_id    integer primary key,
  customer_name  character varying(50) not null,
  phone          character(8) ,
  birth_date     date,
  balance        decimal(7,2)
);

ning tabel customers_archive

CREATE TABLE customer_archive
( 
  customer_id     integer,
  customer_name   character varying(50) not null,
  phone           character(8) ,
  birth_date      date,
  balance         decimal(7,2) ,
  user_changed    varchar,
  date_changed    date,
  operation       varchar
);

Eesmärgiks on kõik customers tabelis toimunud muudatused arhiveerida tabelis customers_archive. Selleks sobib kirjeldada funktsioon

CREATE FUNCTION archive_customer() RETURNS TRIGGER AS $$
  BEGIN
    INSERT INTO customer_archive 
      VALUES
      ( 
        OLD.customer_id,
        OLD.customer_name,
        OLD.phone,
        OLD.birth_date,
        OLD.balance,
        CURRENT_USER,
        now() ,
        TG_OP
      );
    RETURN NULL;
  END;
$$ LANGUAGE 'plpgsql';

Ning lõpuks moodustada trigger archive_customer seostades funktsiooni tabeliga customers

CREATE TRIGGER archive_customer 
  AFTER DELETE OR UPDATE 
  ON customers
  FOR EACH ROW 
    EXECUTE PROCEDURE archive_customer();

Kursorite kasutamine

TODO

Pärilus

Pärilus (ingl. k. inheritance) http://www.postgresql.org/docs/current/interactive/ddl-inherit.html väljendab asjaolu, et PostgreSQL on objekt-relatsiooniline (teatud mõttes objekt-orienteeritud) andmebaas. Nt võimaldab pärilus moodustada tabeleid, mis moodustavad hierarhia, kus üks tabel pärib ühe või mitme muu tabeli omadusi.Päriluse peamiseks kasutusalaks on järgmises punktis kirjeldatud tabeli partitsioneerimine, antud punktis kirjeldatakse päriluse endaga seotud asjaolusid.

Olgu nn master tabel priit.loomad, st tabel mille omadusi mõni teine tabel hakkab pärima selline

CREATE TABLE priit.loomad
(
  loom_id serial NOT NULL,
  liik character varying(50),
  vanus integer,
  nimi character varying(50),
  CONSTRAINT loom_id_pkey PRIMARY KEY (loom_id)
)

Sisaldugu tabelis priit.loomad endas sellised andmed

1  karu  20  Mõmmi
2  hunt  10  Kriim Silm
3  kana   2  Cana

Olgu teine tabel priit.loomad_haruldased, mis pärib tabeli priit.loomad omadusi

CREATE TABLE priit.loomad_haruldased
(
-- Inherited from table priit.loomad_haruldased:  loom_id integer NOT NULL DEFAULT nextval('priit.loomad_loom_id_seq'::regclass),
-- Inherited from table priit.loomad_haruldased:  liik character varying(50),
-- Inherited from table priit.loomad_haruldased:  vanus integer,
-- Inherited from table priit.loomad_haruldased:  nimi character varying(50),
  haruldusaste character varying,
  CONSTRAINT loom_haruldus_id_key PRIMARY KEY (loom_id)
)
INHERITS (priit.loomad)

Sisaldugu priit.loomad_haruldased endas sellised andmed

1  merivart      120  Merra    väga haruldane
2  viiger          1  Vii      haruldane
3  peipsi tink     5  Tint     väga haruldane

Selline konstruktsioonil on järgmised omadused

  • tehes päringuid tabelist priit.loomad saab kasutada kõiki andmeid, st tabelis priit.loomad endas sisalduvaid andmeid ning ka tabeli priit.loomad_haruldased andmeid
sql> select * from priit.loomad;
 loom_id |     liik     | vanus |    nimi    
---------+--------------+-------+------------
       1 | karu         |    20 | Mõmmi
       2 | hunt         |    10 | Kriim Silm
       3 | kana         |     2 | Cana
       1 | merivart     |    12 | Merra
       2 | viiger       |     1 | Vii
       3 | peipsi tink  |     5 | Tint
  • kasutades tabelit priit.loomad_haruldased saab teha efektiivselt päriguid haruldaste loomade kohta
sql> select * from priit.loomad_haruldased;
 loom_id |     liik     | vanus |  nimi  |  haruldusaste  
---------+--------------+-------+--------+----------------
       1 | merivart     |    12 | Merra  | väga haruldane
       2 | viiger       |     1 | Vii    | haruldane
       3 | peipsi tink  |     5 | Tint   | väga haruldane

Andmete sisestamisel peab arvestama, et

  • andmeid saab sisestada nö füüsilisse tabelisse
  • andmeid muutmine toimub ka läbi päriluse, nt
sql> update priit.loomad set vanus='10' where nimi='Tint'; 

Päriluse võimalusi otstarbekalt kasutades on võimalik tekitada selline andmemudel, mis on kompaktne ning võimaldab andmetega efektiivselt töötada.

Olemasolevate tabelite vahel pärimise tekitamiseks või lõpetamiseks sobib öelda vastavalt

alter table priit.loomad_haruldased inherit priit.loomad
alter table priit.loomad_haruldased no inherit priit.loomad

Kasulikud lisamaterjalid

Tabeli partitsioneerimine

Tabeli partitsioneerimise http://www.postgresql.org/docs/current/static/ddl-partitioning.html tulemusena koosneb üks suur loogiline tabel mitmest väiksemast füüsilisest tabelist. Partisioneerimisel on sellised eelised

  • päringu jõudlus suureneb teatud juhtumitel, nt kui päring töötab valdavalt ainult mõnes partitsioonis; efekt toimub muuseas tänu selle, et nt ühe suure indeksi asemel on tegu mitme väiksema indeksiga mis mahub paremine mällu
  • massilised kirjete kustutamised toimuvad oluliselt kiiremini eeldusel, et andmemudel näeb ette võimaluse kustutada kogu kogu partitsiooni
  • harva kasutatavate andmetega partitsioone saab paigutada odavamale ja aeglasemale salvestusseadmele

PostgreSQL andmebaasis saab partitsioneerimist korraldada iseensest kahel viisil

  • toetudes tabeli pärilusele - eelistatud viis, mida järgnevas põhiliselt kirjeldatakse
  • kasutades view ja union võimalusi

Näiteks kirjeldatakse partitsioneeritud tabeli kasutamist pika ajavahemiku jooksul tabelisse loomadsoovad andmete kogumisel. Efekt tuleneb sellest, et suur hulk andmeid jaotatakse aastate kaupa mitmete füüsiliste tabelite vahel ära.

Partitsiooni master tabel partitsioon.loomadsoovad moodustamiseks sobib öelda

CREATE TABLE partitsioon.loomadsoovad
(
  loomadsoovad_id serial NOT NULL,
  kuupaev date,
  rasvad integer,
  valgud integer,
  sysivesikud integer,
  CONSTRAINT loomadsoovad_id_pkey PRIMARY KEY (loomadsoovad_id)
)

ning sellest pärinevad tabelid, oluline on rakendada selliseid piiranguid, et partitsioonides ei oleks korduvaid andmeid

create table partitsioon.loomadsoovad_2005 (
  CHECK ( kuupaev >= DATE '2005-01-01' AND kuupaev < DATE '2005-12-31' ) 
) inherits (partitsioon.loomadsoovad);

create table partitsioon.loomadsoovad_2006 (
  CHECK ( kuupaev >= DATE '2006-01-01' AND kuupaev < DATE '2006-12-31' ) 
) inherits (partitsioon.loomadsoovad);
...

Kirjeldatakse funktsioon

CREATE OR REPLACE FUNCTION partitsioon.loomadsoovad_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO partitsioon.loomadsoovad_2010 VALUES (NEW.*);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

Kirjeldatakse trigger

CREATE TRIGGER insert_loomadsooad_trigger
  BEFORE INSERT
  ON partitsioon.loomadsoovad
  FOR EACH ROW
  EXECUTE PROCEDURE partitsioon.loomadsoovad_insert_trigger();

Andmete sisestamine toimub sellised, kusjuures need andmed satuvad tabelisse partitsioon.loomadsoovad_2010

insert into partitsioon.loomadsoovad (kuupaev, rasvad, valgud, sysivesikud) values ('2010-03-25', '50', '500', '5000');

Partitsiooneeritud tabeli kasutamiseks sobib öelda

select * from partitsioon.loomadsoovad;

või siis ka otse

select * from partitsioon.loomadsoovad_2010;

Märkused

TODO

dblink

dblink tehnika võimaldab ühe andmebaasi päringutes kasutada teise andmebaasi andmeid.

  • Näiteks lihtsalt päringut teha
SELECT *
FROM dblink.dblink('dbname=test host=192.168.10.205 user=postgres','SELECT nimi, vanus FROM priit.priidutabel')
  AS tabelinimi(nimi varchar(50), vanus integer);
  • Tekitada teise andmebaasi andmetest vaade
create view dblink.dblink_view as
  select *
    from dblink.dblink('dbname=test host=192.168.10.205 user=postgres', 'SELECT nimi, vanus FROM priit.priidutabel')
    as tabelinimi(nimi varchar(50), vanus integer);

ja vaate kasutamiseks öelda nt

select * from dblink_view;

pgcrypto

pgcrypto moodul võimaldab kasutada andmebaasis krüptimise funktsioone. Nt md5 vormingus parooli genereerimiseks sobib öelda

 UPDATE pgcrypto.priidutabel SET parool = pgcrypto.crypt('new password', pgcrypto.gen_salt('md5'));

tsearch2

tsearch2 on täisteksti otsingu moodul.

SELECT 'Priit ei ole Mart'::tsvector @@ 'Priit & Mart'::tsquery;
 ?column? 
----------
 t
(1 row)

Protseduurilised keeled

TODO

plpgsql

Lihsamal juhul võiks kirjeldada funktsiooni selline järgnevus

CREATE OR REPLACE FUNCTION liitja (INTEGER, INTEGER) RETURNS INTEGER AS $$
  BEGIN
    return $1 + $2;
  END;
$$ LANGUAGE 'plpgsql';

Funktsiooni kasutamiseks sobib öelda

select liitja(10,50);

Funktsiooni kustutamiseks sobib öelda

drop function liitja(integer, integer);

plproxy

PL/Proxy kasutamiseks peab tarkvara olema paigaldatud ainult sellesse andmebaasi, kust päriguid esitatakse teise andmebaasi.

Teises andmebaasis peab olema kirjeldatud huvipakkuv funktsioon, nt

CREATE OR REPLACE FUNCTION plproxy.liitja(integer, integer)
  RETURNS integer AS
$BODY$
  BEGIN
    return $1 + $2;
  END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE

ja nö esimeses andmebaasis kirjeldatud plproxy keeles funktsioon

CREATE OR REPLACE FUNCTION plproxy.eemal_liitja(arv1 integer, arv2 integer)
  RETURNS text AS
$BODY$
  CONNECT 'dbname=test host=192.168.10.206 user=postgres password=parool';
  SELECT * from plproxy.liitja(arv1, arv2);
$BODY$
  LANGUAGE 'plproxy' VOLATILE

Funktsiooni kasutamiseks sobib öelda esimese baasis

select plproxy.eemal_liitja(50, 100);

Kasulikud lisamaterjalid

plperl

PL/Perl (Perl Procedural Language) http://www.postgresql.org/docs/current/interactive/plperl.html võimaldab kirjutada andmebaasi funktsiooni Perl keeles.

Nt selline funktsioon tegeleb sünniaasta arvutamisega 2010 aastal

CREATE OR REPLACE FUNCTION plpythonu_synniaastaarvutaja(character varying, integer)
  RETURNS character varying AS
$BODY$
 $synniaasta=2010 - $_[1];
 return "Kasutaja: $_[0] synniaasta on: $synniaasta";
$BODY$
  LANGUAGE 'plperlu' VOLATILE

Funktsiooni kasutamiseks tuleb öelda

select plpythonu_synniaastaarvutaja('Priit Kask', '60')

plperlu keeles saab ka operatsioonisüsteemi vahendeid kasutada sh failisüsteemi

 use POSIX qw(locale_h);
 
 open (fh, '>>/tmp/locale.log');
 print fh "start\n";
 $lokaat{LC_CTYPE}=setlocale(LC_CTYPE);
 $lokaat{LC_TIME}=setlocale(LC_TIME);
 $lokaat{LC_COLLATE}=setlocale(LC_COLLATE);
 $lokaat{LC_MESSAGES}=setlocale(LC_MESSAGES);
 $lokaat{LC_MONETARY}=setlocale(LC_MONETARY);
 $lokaat{LC_NUMERIC}=setlocale(LC_NUMERIC);
 
 while ( my ($key, $value) = each(%lokaat) ) {
          print fh "$key => $value\n";
              }
 print fh "end\n";
 close fh;
 
 return "i am print_locale";

plpython

PL/Python (Python Procedural Language) http://www.postgresql.org/docs/current/interactive/plpython.html võimaldab kirjutada andmebaasi funktsiooni Python keeles.

Nt selline funktsioon tegeleb sünniaasta arvutamisega 2010 aasta

CREATE OR REPLACE FUNCTION plpythonu_synniaastaarvutaja(nimi character varying, vanus integer)
  RETURNS character varying AS
$BODY$ 
 synniaasta = 2010 - vanus
 return "Kasutaja: " + nimi + "synniaasta on: " + str(synniaasta)
$BODY$
  LANGUAGE 'plpythonu' VOLATILE

Funktsiooni kasutamiseks sobib öelda

select plpythonu_synniaastaarvutaja('Priit Kask', '60')

pljava

  • Java teegi andmebaasi kopeerimiseks tuleb öelda
 SQL> select sqlj.install_jar('file:///home/mart/helloworld.jar', 'helloworld_jar',  false);

Kusjuures baasi laaditud java teekide nimekirja saab küsida

 SQL> select jarname, jarorigin from sqlj.jar_repository;
  • Seostame selle skeemiga, kust PL/Java funktsioone kasutatakse classpath'i öeldes
 SQL> SELECT sqlj.set_classpath('skeeminimi', 'helloworld_jar');
  • PL/Java funktsiooni tekitamine
 CREATE OR REPLACE FUNCTION helloworld()
   RETURNS "varchar" AS
     'com.mycompany.helloworld.HelloWorld.helloWorld'
   LANGUAGE 'java' VOLATILE;
  • PL/Java funktsiooni käivitamine
 SQL> select * from helloworld();
  • PL/Java funktsiooni kasutamine plpgsql funktsioonist
 CREATE OR REPLACE FUNCTION testlocale() RETURNS TIMESTAMP AS
 $body$
 DECLARE
   dummy timestamp;
 BEGIN
   perform helloworld();
   dummy := current_timestamp;
   return dummy;
 END;
 $body$
 LANGUAGE 'plpgsql';

Failisüsteemi kasutamine

Failisüsteemi salvestamine

Andmebaasist päringu tulemuse kopeerimiseks failisüsteemi sobib nt esmalt moodustada ajutine tabel priit.nimed

CREATE TEMP TABLE nimed AS SELECT nimi FROM priit.priidutabel;

ning seejärel tabeli sisu salvestada failisüsteemi öeldes

copy nimed to '/tmp/priit.log';

Failisüsteemist lugemine

Olemasolevasse tabelisse priit.priidutabel failisüsteemi failist /tmp/andmed andmete kopeerimiseks sobib öelda

copy priit.priidutabel (vanus, nimi) from '/tmp/andmed' with delimiter ' ';

Aja kasutamine

PostgreSQL andmebaasis saab aega esitada viiel moel

  • timestamp without time zone - kuupäev ja kellaaeg ilma ajatsoonita
  • timestamp with time zone - kuupäev ja kellaaeg ajatsooniga
  • data - kuupäev
  • time without time zone - kellaaeg ilma ajatsoonita
  • time with time zone - kellaaeg ajatsooniga
  • interval - ajavahemik

Aja väljendamine sisendis ja väljundis

PostgreSQL lubab väljandada aega sisendis üsna paindlikult, nt töötavad sellised variandid

sql> select timestamp '2010-03-27 22:44:55';
      timestamp      
---------------------
 2010-03-27 22:44:55
sql> select timestamp with time zone '2010-03-27 22:44:55';
      timestamptz       
------------------------
 2010-03-27 22:44:55+02
sql> select date 'Mar 27 2010';
    date    
------------
 2010-03-27
sql> select date '27 Mar 2010';
    date    
------------
 2010-03-27

Vaikimisi väljendatakse aega väljundis igal juhtumil ISO standardile vastavalt.

Tehted ajaga

Põhiliselt kasutatakse seoses ajaga kahte tehet: liitmine/lahutamine ja võrdlus. Seejuures on abiks ajavahemiku tüüp 'interval'.

  • liitmine ja lahutamine, nt arvutame kellaaja 9 päeva ja 23 minutit tagasi
sql> select current_timestamp - interval '9 days 23 minutes';
           ?column?            
-------------------------------
 2010-03-18 23:39:08.328026+02
  • võrdlus, nt võrdleme, kas inimene on sündinud enne või peale 1. jaanuar 1980
CREATE OR REPLACE FUNCTION kunassyndis(timestamp)
  RETURNS character varying AS
$BODY$
  declare
  synniaeg timestamp;
  vastus varchar(50);
begin
    synniaeg = $1;
    if synniaeg < '1980-01-01' then
       vastus = 'Sündinud enne 1. jaanuar 1980';
    else
       vastus = 'syndinud peale 1. jaanuar 1980';
    end if;
    return vastus;
end;
    $BODY$
LANGUAGE 'plpgsql' VOLATILE

Binary andmete hoidmine andmebaasis

Vt http://kuutorvaja.eenet.ee/wiki/Python#Binary_andmete_sisestamine

Kasulikud lisamaterjalid