Documente Academic
Documente Profesional
Documente Cultură
BAZELOR DE DATE
ÎNDRUMAR DE LABORATOR
Liviu Şerbănescu
UNIVERSITATEA HYPERION
LISTA LUCRĂRILOR
1. Funcții SQL;
2. Crearea bazelor de date, a sesiunilor şi a utilizatorilor. Creare tabele cu diverse tipuri de
câmpuri;
5. Combinarea interogărilor
7. Expresii condiţionale
10. Moştenirea;
11. Subinterogări
14. Teste.
LABORATORUL NR.1
FUNCȚII SQL
Scop:
1. Introducere în server-side programing
2. Înţelegerea funcțiilor SQL
Exemplificare:
-----------------------------------------------------------------------------
--functia c1.ftest0() NU preia si NU intoarce valori
CREATE OR REPLACE function cx.ftest0()
RETURNS void AS
$$
DROP TABLE IF EXISTS t1;
CREATE TEMP TABLE t1(a1 serial PRIMARY KEY ,a2 int, a3 int, a4 varchar(20));
$$
LANGUAGE 'sql';
-- corpul functiei este incadrat de $$ sau $BODY$ si contine doar o comanda SQL
-----------------------------------------------------------------------------
-- apelul functiei (executia functiei)
----------------------------------------------------------------------------
-- functie SQL ptr. afisarea continutului lui t1 ---VARIANTA2
CREATE OR REPLACE function cx.ftest3()
RETURNS SETOF RECORD AS -- RECORD este tipul inregistrare -- un grup de campuri
$$
SELECT a1,a2,a3,a4 FROM t1
$$
LANGUAGE 'sql';
-----------------------------------------------------------------------------
--apel functie --- varianta A
-- daca apelam SELECT a1,a2,a3,a4 FROM c1.ftest3() NU cunoaste numele campurilor
SELECT cx.ftest3(); -- rezultat pe o singura coloana
-- apel functie --- varianta B
SELECT a1,a2,a3,a4 FROM cx.ftest3() AS (a1 int,a2 int, a3 int, a4 varchar(20));
-- in AS este definita structura RECORD
--rezultatul apare pe patru coloane
------------------------------------------------------------------------------
-- functie SQL ptr. afisarea continutului lui t1 --VARIANTA3
CREATE OR REPLACE function cx.ftest4()
RETURNS SETOF t1 AS
$$
SELECT a1,a2,a3,a4 FROM t1
$$
LANGUAGE 'sql';
---------------------------------------------------------------------------
--apel functie --- varianta A
SELECT cx.ftest4(); -- campurile sunt agregate intr-un singur camp de tip structura de date
-- apel functie --- varianta B
SELECT * FROM cx.ftest4(); -- intoarce tabel-- deoarece a1,a2,a3,a4 sunt deja definite
-- apel functie --- varianta C
SELECT a1,a2,a3 as w3,a4 FROM cx.ftest4(); -- campurile sunt afisate distinct
--tipul fiecarui camp este cunoscut din "RETURNS SETOF c1.t1"
----------------------------------------------------------------------------
-- functie SQL ptr. afisarea continutului lui t1 --VARIANTA4
CREATE OR REPLACE function cx.ftest5()
RETURNS SETOF RECORD AS
$$
SELECT a1,a2,a3,a4 FROM t1
$$
LANGUAGE 'sql';
---------------------------------------------------------------------------
--apel functie --- varianta A
SELECT cx.ftest5(); -- grupeaza campurile
-- apel functie --- varianta B
--SELECT * FROM c1.ftest5();-- nu cunoaste structura inregistrarii
--SELECT a1,a2,a3,a4 FROM cx.ftest5();--err: nu cunoaste structura inregistrarii
SELECT a1,a2,a3,a4 FROM cx.ftest5() AS (a1 int,a2 int, a3 int, a4 varchar(20));
--------------------------------------------------------------------------------
Desfăşurarea lucrării:
1. Se lansează interfaţa pgAdmin3
2. Se introduc funcții descrise în secțiunea exemplificare
3. Se testează
4. Se extind cerințele pentru alte tipuri de argumente
5. Se extinde lista de argumente
6. Se testează
7. Se trag concluzii
LABORATORUL NR.2
INTRODUCERE ÎN plpgSQL
Scop:
1. Înţegerea conceptelui privind plpgSQL
2. Construcția câtorva funcții simple de tip plpgSQL
Exemplificare
----- PROCEDURI plpgsql --------------
-- sunt de cateva ori mai lente decat functiile SQL insa sunt mult mai flexibile
-- Function: c10.gtest1()
-- Function: c1.gtest2()
--------------------------------------------------
select cx.f1(5,7); -- campul rezultat are numele functiei
--------------------------------------------------
select * from cx.f1(4,9); -- campul rezulta are numele variabilei de iesire
-----------------------------------------------------------------------
create or replace function cx.f2(a int, IN b int,OUT suma int, OUT produs int, OUT impartire
numeric) as
$$
BEGIN -- nu am pus RETURNS
-- sunt recunoscute denumirile variabilelor
suma:=a+b;
produs:=a*b;
impartire:=a/(b*1.0);
END
$$
language plpgsql;
--------------------------------------------------------------------------------------------
-- operatii elementare cu notificari in plpgsql
create or replace function cx.f3() returns text as
$$
DECLARE
nr_ins int; --nr linii adaugate/inserate
nr_up int; --nr. linii modificate
achR text;
total int;
BEGIN
achR:='OK';--textul este marginit de apostrof
DROP TABLE IF EXISTS t4;
CREATE TEMP table t4(a serial PRIMARY KEY, b int, c varchar(10));
INSERT INTO t4(b,c) VALUES (11,'A1'),(21,'B2'),(31,'B3'),(41,'C3');
-- GET DIAGNOSTICS intoarce valori ale variabilelor setate in urma executiei ultimei
comenzi
GET DIAGNOSTICS nr_ins = ROW_COUNT;
-- RAISE NOTICE -- creaza o NOTIFICARE de la server catre client
RAISE NOTICE 'Au fost adaugate: % inregistrari',nr_ins;
-- asemanator cu structura formatului de la printf,, in loc de % pune valoarea din
variabila nr_ins
UPDATE t4 SET b=b+2 WHERE c LIKE 'B%';
GET DIAGNOSTICS nr_up = ROW_COUNT; RAISE NOTICE 'Au fost actualizate:
% inregistrari',nr_up;
SELECT sum(b) FROM c1.t4 INTO total;
if total < 60 then achR:='NOK'; end if;
return achR;
END
$$ language plpgsql;
-- select nextval('c10.t1_a_seq');
select c1.f3();
-- Function: c10.gtest1()
---------------------------------------------------------
--EXEMPLU ADAUGA o INREGISTRARE DACA NR. ACESTORA (inainte de adaugare)
ESTE IMPAR
--SI DOUA INREG. DACA NR. DE INREG ESTE par
-- Function: c1.gtest2()
--------------------------------------------------
select cx.f1(5,7); -- campul rezultat are numele functiei
--------------------------------------------------
select * from cx.f1(4,9); -- campul rezulta are numele variabilei de iesire
-----------------------------------------------------------------------
create or replace function cx.f2(a int, IN b int,OUT suma int, OUT produs int, OUT impartire
numeric) as
$$
BEGIN -- nu am pus RETURNS
-- sunt recunoscute denumirile variabilelor
suma:=a+b;
produs:=a*b;
impartire:=a/(b*1.0);
END
$$
language plpgsql;
--------------------------------------------------------------------------------------------
-- operatii elementare cu notificari in plpgsql
create or replace function cx.f3() returns text as
$$
DECLARE
nr_ins int; --nr linii adaugate/inserate
nr_up int; --nr. linii modificate
achR text;
total int;
BEGIN
achR:='OK';--textul este marginit de apostrof
DROP TABLE IF EXISTS t4;
CREATE TEMP table t4(a serial PRIMARY KEY, b int, c varchar(10));
INSERT INTO t4(b,c) VALUES (11,'A1'),(21,'B2'),(31,'B3'),(41,'C3');
-- GET DIAGNOSTICS intoarce valori ale variabilelor setate in urma executiei ultimei
comenzi
GET DIAGNOSTICS nr_ins = ROW_COUNT;
-- RAISE NOTICE -- creaza o NOTIFICARE de la server catre client
RAISE NOTICE 'Au fost adaugate: % inregistrari',nr_ins;
-- asemanator cu structura formatului de la printf,, in loc de % pune valoarea din
variabila nr_ins
UPDATE t4 SET b=b+2 WHERE c LIKE 'B%';
GET DIAGNOSTICS nr_up = ROW_COUNT; RAISE NOTICE 'Au fost actualizate:
% inregistrari',nr_up;
SELECT sum(b) FROM c1.t4 INTO total;
if total < 60 then achR:='NOK'; end if;
return achR;
END
$$ language plpgsql;
-- select nextval('c10.t1_a_seq');
select c1.f3();
Desfăşurarea lucrării:
1. Se execută exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.3
INSTRUCȚIUNI CICLICE ÎN plpgSQL
Scop:
Utilizarea buclelor în cadrul plpgSQL
Exemplificare:
-- SELECT c3.f0(ARRAY[4,2,1]);
----------------------------------------------------------------------------
--INSTRUCTIUNI CICLICE
LOOP
--- bloc instructiuni
END LOOP;
-- iesirea din bucla se realizeaza cu instructiunea EXIT (echivalent break in c++)
-- revenirea la inceputul buclei (fara executarea restului de instructiuni) se realizeaza cu instr.
CONTINUE (idem in C++)
/*
i:=0;
LOOP
--- instr.
IF i<10 THEN CONTINUE; END IF;
IF i>100 THEN EXIT; END IF;
-- instructiuni in care i este intre 10 si 100
END LOOP;
*/
------------------------------------------------------------------
WHILE
-- conditie (expresie evaluata la true --- adica diferita de 0)
LOOP
--instructiuni
END LOOP;
-----------------------------------------------
FOR nume IN expresieDomeniu
LOOP
--instructiuni
END LOOP;
-------------------------------------------
FOR i IN 1..100
LOOP
--
-- i are valori de la 1 la 100
END LOOP;
-------------------------------------------------------------
FOR r IN TABEL --aici expresieDomeniul este alcatuit din multimea liniilor tabelului
LOOP
--
-- r este variabila ce contine o inregistrare (linie de tabel)
-- r parcurge tot tabelul (la fiecare ciclu preia o alta inregistrare din tabel)
END LOOP;
--------------------------------------------------------
-- functie contor
create or replace function f0_1(_start_ int) RETURNS int AS
$$
DECLARE
i int; j int;
begin
i:=_start_; j:=0; -- i:=$1; j:=0;
LOOP
i:=i+1;
j:=j+1;
if j=100 then exit; end if;
END LOOP;
return i;
end
$$ language plpgsql;
select f0_1(17);
----------------------------------------------------------------------------------------
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea exemplificări
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.4
CONSTRUCȚIA FUNCȚIILOR DINAMICE ÎN plpgSQL
Scop:
Construcția funcțiilor plpgSQL ce permit execuția de comenzi SQL ce se construiesc în
momentul execuției funcției pe baza datelor transmise prin argument și a altor date.
Exemplificare:
CREATE SCHEMA c4;
--functii dinamice --- comenzile sunt reprezentate prin siruri de caractere ce se formeaza
--in momentul apelarii functiei
--ex2: sa se scrie o funcie/procedura ce preia un tablou cu siruri de caractere ce reprezinta filtre
--pentru o selectie din t1 si creaza un tabel t2 cu rezultatul selectiei
drop table if exists t1;
create temporary table t1(idx serial, val varchar(20));
insert into t1(val) values ('A111'),('A222'),('A333'),('A222'),('B111');
select * from t1;
----------------------------------------------------------------------------
--functie ce preia un vector cu valori pentru un filtru
create or replace function c4.f0(_filtru_ text[]) --preia un vector cu siruri de caractere
RETURNS void AS
$$
DECLARE
achQ text; -- vom pune comanda SQL pentru interogare
i int;
BEGIN
--sirul preluat se termina cu NULL
achQ:='DROP TABLE IF EXISTS t2; CREATE TEMP TABLE t2 as SELECT * FROM t1 WHERE ';
i:=1;
LOOP
IF _filtru_[i] IS NULL THEN achQ:=achQ||';'; EXECUTE achQ;
RAISE NOTICE 'sirul format: % ',achQ;
RETURN ; END IF;
IF i>1 THEN achQ:=achQ||' OR '; END IF;
achQ:=achQ||' val='||quote_literal(_filtru_[i]);
i:=i+1;
-- where val='...' or val=... or val=...
END LOOP;
END
$$
LANGUAGE 'plpgsql';
-----------------------------------------------------
-- cuvantul cheie EXECUTE lansaseaza pentru executie comanda formata din sirul de de caractere
-- functia plpgsql quote_literal(...) adauga apostrof pentru sirul din argument, aceasta functie
reduce numarul simbolurilor '
-- din cadrul plpgsql, pentru scrierea intr-un sir delimitat cu apostrof a unui apostrof este necesarea
adaugarea a inca unui apostrof
-- in fata acestuia
-----------------------
select * from t1;
--afiseaza doar liniile ce cuprind valorile A222 sau A333
SELECT c4.f0(ARRAY['A222','A333',NULL]);
select * from t2;
-----------------------------------------------------------------
Desfăşurarea lucrării:
1. Se rulează exemplul din secţiunea exemplificare
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.5
CREAREA TRIGGERE--LOR
Scop:
1. Controlul evenimentelor de editare prin implementarea triggere-lor
2. Testarea execuției triggere-lor
Exemplificări
/*
Pentru captarea evenimentelor de editare a unui tabel (insert,update,delete)
pot fi utilizate functii/proceduri speciale ce pot fi apelate automat de
SGBD in momentul aparitiei unui eveniment de editare asupra unui tabel.
De asemenea, in cazul unui eveniment de tip UPDATE aceste functii/proceduri
speciale au acces atat la vechile valori cat si la noile valori din cadrul campurilor liniei
care se modifica.
*/
/*Ex: Construim un tabel care afiseaza data si anul.
Daca mosdificam data, celelalte campuri trebuie se actualizeze automat anul
fara a apela explicit vreo functie*/
drop table if exists c5.t1;
CREATE TABLE c5.t1(datac date, an smallint,idx serial PRIMARY KEY);
-- In functia de tip triger NEW si OLD sunt predefinite si sunt de tip RECORD
-- acestea memoreaza noua, respectiv vechea valoare a inregistrarii afectate
-- CREAREA FUNCTIEI DE TIP TRIGGER
---------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION c5.f1()
RETURNS trigger AS
$$
BEGIN
SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an;
return NEW;
END
$$
LANGUAGE 'plpgsql';
---------------------------------------------------------------------------------------------------
--- ATASAREA FUNCTIEI DE TIP TRIGER UNUI TABEL
CREATE TRIGGER t1_trg
BEFORE UPDATE
ON c5.t1
FOR EACH ROW
WHEN ((old.* IS DISTINCT FROM new.*))
EXECUTE PROCEDURE c5.f1();
-------------------------------------
--verificare
INSERT INTO c5.t1(datac) VALUES('2013-03-15'); -- campul anul nu este modificat deoare functia
triger
-- este setata sa raspundda doar la evenimente de tipul update
select * from c5.t1;
UPDATE c5.t1 SET datac=datac+2;-- este apelata automat functia triger
select * from c5.t1;
-----------------------------------------------------------------
/* EX:Construim un tabel care afiseaza data si anul_v -inainte de modificare si -anul_n -dupa
modificare.
Daca mosdificam data, celelalte campuri trebuie se actualizeze automat anul
fara a apela explicit vreo functie*/
drop table if exists c5.t2;
CREATE TABLE c5.t2(datac date, an_v smallint, an_n smallint,idx serial PRIMARY KEY);
---------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION c5.f2()
RETURNS trigger AS
$$
BEGIN
SELECT EXTRACT( YEAR FROM OLD.datac) INTO NEW.an_v;
SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an_n;
return NEW;
END
$$
LANGUAGE 'plpgsql';
---------------------------------------------------------------------------------------------------
--- ATASAREA FUNCTIEI DE TIP TRIGER UNUI TABEL
CREATE TRIGGER t2_trg
BEFORE UPDATE
ON c5.t2
FOR EACH ROW
WHEN ((old.* IS DISTINCT FROM new.*))
EXECUTE PROCEDURE c5.f2();
---------------------------------------------------------------------------------------------------
--verificare
INSERT INTO c5.t2(datac) VALUES('2013-03-15'); -- campul anul nu este modificat deoare functia
triger
-- este setata sa raspundda doar la evenimente de tipul update
select * from c5.t2;
UPDATE c5.t2 SET datac=datac+2022;-- este apelata automat functia triger
select * from c5.t2;
/*
construim un tabel t3 cu 2 coloane: nr. zilei din saptamana, denumirea zilei si un camp idx
In momentul introducerii nr. zilei - daca este intre 1-7 se va afisa denumirea acesteia
altfel nr. zilei ramane nemodificat
*/
---------------------------------------------------------------------------------------------------
drop table if exists c5.t3;
create table c5.t3(nz smallint,denzi varchar(15),idx serial PRIMARY KEY);
---------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION c5.f3()
RETURNS trigger AS
$$
BEGIN
IF NEW.nz=1 THEN NEW.denzi='Luni'; END IF;
IF NEW.nz=2 THEN NEW.denzi='Marti'; END IF;
IF NEW.nz=3 THEN NEW.denzi='Miercuri'; END IF;
IF NEW.nz=4 THEN NEW.denzi='Joi'; END IF;
IF NEW.nz=5 THEN NEW.denzi='Vineri'; END IF;
IF NEW.nz=6 THEN NEW.denzi='Sambata'; END IF;
IF NEW.nz=7 THEN NEW.denzi='Duminica'; END IF;
IF NEW.nz<1 OR NEW.nz>7 THEN OLD.denzi=NULL; return OLD;
ELSE return NEW; END IF;
END
$$
LANGUAGE 'plpgsql';
---------------------------------------------------------------------------------------------------
CREATE TRIGGER t3_trg
BEFORE UPDATE
ON c5.t3
FOR EACH ROW
WHEN ((old.* IS DISTINCT FROM new.*))--implicit condtitia de aplicare a trigeru-lui este cand
una din valorile noi difera
-- dar poate fi aplicate si coditii mai complexe asemanatoare celor sin conditia WHEN din cadrul
comenzii SELECT
EXECUTE PROCEDURE c5.f3();
---------------------------------------------------------------------------------------------------
--verificare
INSERT INTO c5.t3(nz) VALUES(NULL); -- campul anul nu este modificat deoare functia triger
-- este setata sa raspundda doar la evenimente de tipul update
select * from c5.t3;
UPDATE c5.t3 SET nz=2;-- este apelata automat functia triger
select * from c5.t3;
--IN CAZUL TRIGGER-ului pentru INSERT NU exista inregistrarea OLD, ci numai NEW
DROP TRIGGER IF EXISTS t4_trg ON c5.t3;
---
---------------------------------------------------------------------------------------------------
DROP TABLE IF EXISTS c5.t5; CREATE TABLE c5.t5( idx serial PRIMARY KEY, nz smallint);
INSERT INTO c5.t5(nz) VALUES (15),(20),(25);
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea exemplificări
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.6
FUNCȚII UTILIZATE PE PARTEA SERVER SIDE
Scop:
Utilizarea funcțiilor postgreSQL cu utilizare specifică în plpgSQL.
Exemplificări:
--------------------------------------------------------------------------------------------------------
--utilizare functiilor quote_ident() si quote_literal() in constructia interogarilor dinamice
--------------------------------------------------------------------------------------------------
-- FUNCTII UZUALE
SELECT CURRENT_DATE;
SET datestyle TO German;
SELECT CURRENT_DATE;
SET datestyle TO SQL,'MDY';
SELECT CURRENT_DATE;
SET datestyle TO Postgres;
SELECT CURRENT_DATE;
Exemplificări:
--TIPURI DE DATE DEFINITE DE UTILIZATOR
create schema c9;
DROP TYPE IF EXISTS adresa01 CASCADE;
-- sunt asemanatoare cu definirea structurilor in C
CREATE TYPE adresa01 AS
(
tara varchar(30),
regiune varchar(30),
oras varchar(40),
str varchar(50),
nr int,
cod_postal int,
tel varchar(20),
e_mail varchar(20)
);
-- in cadrul cond.
SELECT * FROM c9.pers WHERE (adresa).oras ilike '%bv%';
--sau
SELECT * FROM c9.pers WHERE adresa =
'(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,50006,''-'',''-'')'::adresa01;
--Fara a avea operatori definiti explicit pentru acest tip de dat sunt utilizati operatorii standard
-- ce aplica pe rand fiecarui tip de data din cadrul structurii definitite de utilizator
SELECT * FROM c9.pers WHERE adresa <
'(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,50006,''-'',''-'')'::adresa01;
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea exemplificari
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.8
SUPRAÎNCĂRCAREA OPERATORILOR
Scop:
Supaîncărcarea operatorilor SQL pentru tipurile de date definite de utilizator
Exemplificare:
-- Daca dorim ca sa existe egalitate intre doua adrese cu informatii partial introduse dar
-- suficiente pentru identidicare este necesar sa rescriem/supraincarcam operatorul SQL de
egalitate
--intoarce true daca cele doua adrese sunt din acelasi oras
CREATE OR REPLACE FUNCTION c9.op_egal_niv_oras(_a_ adresa01, _b_ adresa01)
RETURNS boolean AS
$BODY$
BEGIN
IF ($1.tara = $2.tara AND $1.oras=$2.oras) OR $1.cod_postal=$2.cod_postal THEN RETURN
TRUE; END IF;
RETURN FALSE;
END
$BODY$
LANGUAGE 'plpgsql';
--operatorul de indexare (implicit ptr. indexare SGBD-ul utlizeaza btree-- arbore binar)
CREATE OR REPLACE FUNCTION c9.op_btree(_a_ adresa01, _b_ adresa01)
RETURNS integer AS
$BODY$
BEGIN
IF $1.tara<$2.tara OR ($1.tara=$2.tara and $1.oras < $2.oras)
OR ($1.tara=$2.tara and $1.oras = $2.oras and $1.str < $2.str)
OR ($1.tara=$2.tara and $1.oras = $2.oras and $1.str = $2.str and $1.nr<$2.nr)
THEN RETURN -1;
END IF;
IF $1.tara>$2.tara OR ($1.tara=$2.tara and $1.oras > $2.oras)
OR ($1.tara=$2.tara and $1.oras = $2.oras and $1.str > $2.str)
OR ($1.tara=$2.tara and $1.oras = $2.oras and $1.str = $2.str and $1.nr>$2.nr)
THEN RETURN 1;
END IF;
RETURN 0;
END;
$BODY$
LANGUAGE plpgsql ;
-- simbol operator -- functia apelanta -- tip argument stanga --- tip argument dreapta
CREATE OPERATOR ==(
PROCEDURE = c9.op_egal_niv_tara,
LEFTARG = adresa01,
RIGHTARG = adresa01);
--familia de operatori
--CREATE OPERATOR FAMILY adresa01_operatii USING btree;
select * from c9.pers where adresa=='(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,50006,''-'',''-'')'::adresa01;
--ordonare
select * from c9.pers order by adresa;
--test dublplicate
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea exemplificari
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.9
INTEROGAREA CU DATE DE TIP TABLOU
Scop:
Dezvoltarea interogarilor ce cuprind date de tip tablou.
:
--teste
drop table if exists t1;
create temp table t1(a serial primary key, b int[]);
insert into t1(b) values (array[10]),(array[10,20]),(array[20,30,40]),(array[10,20,30]);
select * from t1;
-- pentru a utiliza elemente dintr-un data de tip tablou se utilizeaza functia generate_subscripts
-- expandeaza tabloul -- fiecare noua inregistrare va contine cate o celula
-- cazul de mai jos tablou cu o dimensiune
select b, s, b[s] as "celula b[s]" FROM (select b, generate_subscripts(b,1) as s from t1)par
-- ex: selecteaza toate celule care au valoarea 30
select b, s, b[s] as "celula b[s]" FROM (select b, generate_subscripts(b,1) as s from t1)par
WHERE b[s]=30;
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
generale, implementate la nivel de server şi un grup specific
de restricţii dat de nivelul cel mai de jos al restricţiilor.
n
SELECT Server Side : RD - Restriction function (F RD )
AND
nx
Local group : RD - Restriction function (F RD )
AND
Application restrictions
n
UPDATE Server Side : WR - Restriction function (F WR )
AND
nx
Local group :WR - Restriction function (F WR )
DELETE AND
Application restrictions
Implementarea restricţiilor
--creare utilizatori
--DROP ROLE student21;
CREATE ROLE student21 LOGIN PASSWORD '123' -- (student21 este
<username>)
NOSUPERUSER NOINHERIT NOCREATEDB NOCREATEROLE CONNECTION LIMIT 1;
-- CONNECTION LIMIT 1 --->este permisa o singura conexiune pentru
utilizator (nu pot intra simultan doi utilizatotori cu acelasi <username>
)
--atrbuire pentru student21 a drepturilor de acces specifice grupului
"CONSULTARE2"
--Pentru un GRUP
--1. Se ofera acces la nivel de BAZA DE DATE
GRANT CONNECT ON DATABASE "CURS_BD2012" TO "CONSULTARE2";
GRANT CONNECT ON DATABASE "CURS_BD2012" TO "EDITARE2";
GRANT ALL ON DATABASE "CURS_BD2012" TO "SUPERVIZOR2";
/* NOTA:
PENTRU TESTAREA DREPTURILOR DE ACCES DIN pgAdmin3
se va deconecta serverul de baze de date curent
si se va reintra cu numele si parola utilizatorului ales
-- se vor testa drepturi ptr.: creare obiecte(database,schema, tabel,etc)
stergere inregistrari
actualizare inregistrari
inserare inregistrari
pentru cele 3 campuri ale tabelului.
*/
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică
2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
TESTE REZOLVATE
--------------------------------------------------------------------------------------------------------
II. Într-o parcare sunt înregistrate:nr.înmatric, data calendarică şi timpul (oră,min etc.)
--pentru intrarea/ieşire în/din parcare.
--create table c6.parc( nrinm varchar(20), datac date, ora time, CONSTRAINT kx PRIMARY
KEY(nrinm,datac,ora))
-- 1.să se scrie o funcţie ce preia numărul de înmatriculare şi verifică dacă autovehicolul se află sau
nu în parcare
-- 2.să se scrie o funcţie ce preia numărul de înmatriculare şi întoarce durata ultimei
--staţionări în parcare (auotovehiculul poate fi încă în parcare sau nu)
/*
DELETE FROM c6.parc;
INSERT INTO c6.parc VALUES ('B-45-ABC','2014-02-05','12:24'),('B-47-ADC','2014-02-05','12:44'),
('B-45-ABC','2014-02-05','18:24'),('B-48-ABC','2014-02-05','12:24'),
('B-45-ABC','2014-07-05','12:24'), ('B-45-ABC','2014-07-08','1:15');
select * from c6.parc;
*/
CREATE OR REPLACE function c6.vfparc(_nrinm_ varchar(20),OUT exista boolean)
AS
$$
DECLARE nr int;
BEGIN
select COUNT(*) FROM c6.parc WHERE nrinm=_nrinm_ INTO nr;
exista:=nr%2;
END
$$ language 'plpgsql';
SELECT c6.vfparc('B-45-ABC');
----------------------------------
--var 2
CREATE OR REPLACE function c6.durataparc2(_nrinm_ varchar(20),OUT durata interval)
AS
$$
DECLARE exista boolean;
r record;
t1 timestamp;
t2 timestamp;
i int;
BEGIN
SELECT c6.vfparc(_nrinm_) INTO exista;
IF NOT exista THEN
i:=2;
FOR r IN SELECT * FROM c6.parc WHERE nrinm=_nrinm_ ORDER BY datac DESC,ora DESC
LIMIT 2
LOOP
if i=2 then t2:=r.datac+r.ora; end if;
if i=1 then t1:=r.datac+r.ora; end if;
i:=i-1;
END LOOP;
ELSE
SELECT datac+ora FROM c6.parc WHERE nrinm=_nrinm_ ORDER BY datac DESC,ora DESC
LIMIT 1 INTO t1;
SELECT CURRENT_DATE+CURRENT_TIME INTO t2;
END IF;
durata:=t2-t1;
END
$$ language 'plpgsql';
SELECT c6.durataparc2('B-45-ABC');
---------------------------------------------------------------------------
-- să scrie o inter. care întoarce numărul de maşini existente în parcare
CREATE OR REPLACE function c6.nrparc(OUT nr int)
AS
$$
DECLARE
BEGIN
SELECT COUNT(*) FROM (SELECT nrinm FROM c6.parc GROUP BY nrinm HAVING count(*)%2 <>
0 ) par INTO nr;
END
$$ language 'plpgsql';
---------------------------------------------------------------------------
SELECT c6.nrparc();
select current_date+current_time
2. Se dă un tabel având structura (a date (PK), b numeric). Să se scrie o funcţie ce preia un interval
dată calendaristică şi întoarce înregistrările care au data cuprinsă în intervalul dat iar fiecare
valoare a campului b va fi media aritmetică formată din valoarea lui b din inregistrarea curentă, din
înregistrarea anterioară şi din înregistrarea urmatoare. Dacă valoarea anterioară sau următoare nu
există se va considera valoarea zero.
#T2
A1. Să se scrie o funcţie plpgsql ce preia doi vectori _a_[ ] şi _b_[ ] ce conţin date de tip întreg.
Ultimul element din fiecare vector este NULL. Execuţia funcţiei va avea ca rezultat doi vectori.
Primul vector va conţine reuniunea celor doi vectori iar al doilea vector va conţine intersecţia celor
doi vectori.
A2. Se dă un tabel ce conţine evidenţa intrărilor într-o parcare şi altul care conţine evidenţa ieşirilor
din parcare. Fiecare tabel va avea câmpurile: data calendaristică, ora (format time) şi numărul de
îmnatriculare. Să se scrie o funcţie plpgsql ce întoarce un tabel cu autoturismele existente în
parcare, acesta va conţine numărul de îmnatriculare, data calendaristică şi ora intrării în parcare.
A3. Se dă un tabel cu denumirea NOM ce conţine câmpurile cod_produs şi tva şi un alt tabel cu
denumirea NIR conţine câmpurile: cod_produs, val_fara_tva, val_cu_tva. Să se scrie codul necesar
implementării unui trigger pentru operaţia de actualizare a câmpului val_cu_tva. În cazul în care nu
exista valoare corespondentă pentru tva câmpul val_cu_tva va fi NULL.
B1. Se dă un tabel ce contine un câmp de tip varchar(20) [ ] (vector cu date de tip varchar(20)). Să
se scrie o funcţie plpgsql ce preia o dată de tip (varchar(20) ) _m_ şi întoarce TRUE dacă valoarea
lui _m_ se regăseşte în tabel, altfel întoarce FALSE.
B2. Să se scrie codul necesar pentru implementarea unei structuri definite de utilizator (denumită
eveniment) ce conţine: data calendaristică, ora (de tip time), utilizator, cod_eveniment (de tip
varchar). Se vor alege operatorii ce vor fi supraîncărcaţi şi operaţiile asociate acestora.