Bazy danych - cwiczenia

Transkrypt

Bazy danych - cwiczenia
PL/SQL
Ćwicznia 2
4. Napisać kod bloku animowanego w PL/SQL, za pomocą którego z tabeli osoby
będzie można wybrać osobę o określonym nazwisku i imieniu, przy czym
nazwisko i imię tej osoby jest podane poprzez zainicjowanie dwóch
odpowiednich zmiennych PL/SQL. Należy wyświetlić pozostałe dane tej osoby.
Poszukujemy nazwisko i imię Lis Jan.
DECLARE
o_Imie1 VARCHAR(20):='Jan';
o_Nazwisko VARCHAR(20):='Lis';
BEGIN
SELECT imie1,nazwisko
INTO o_Imie1, o_Nazwisko
FROM osoby
WHERE imie1=o_Imie1, INITCAP(nazwisko)=o_Nazwisko;
DBMS_OUTPUT.PUT_LINE(o_Imie ||' '|| o_Nazwisko);
END;
4a) Napisać kod bloku animowanego w PL/SQL, za pomocą którego z tabeli osoby
będzie można wybrać osobę o określonym nazwisku i imieniu, przy czym
nazwisko i imię tej osoby jest podane poprzez zainicjowanie jednej zmiennej
PL/SQL wartością Lis Jan. Należy wyświetlić pozostałe dane tej osoby.
DECLARE
o_dane VARCHAR(20):='Jan Lis';
BEGIN
SELECT imie1 ||' '|| nazwisko dane
INTO o_dane
FROM osoby
WHERE imie1 ||' '|| INITCAP(nazwisko)=o_dane;
DBMS_OUTPUT.PUT_LINE(o_dane);
END;
Ćwiczenia 3
1'. Napisać kod bloku animowanego języka PL/SQL za pomocą którego będzie
można wyświetlić tę osobę( nazwisko, imię, pensja) które jest aktualnie
zatrudniona i aktualnie pobiera maksymalną pensje, przy czym płeć tej osoby
jest zainicjowana przez odpowiednią zmienną.
DECLARE
o_Plec CHAR(1):='K';
o_Nazwisko VARCHAR(20);
o_Imie1 VARCHAR(20);
p_Pensja NUMBER(2);
BEGIN
SELECT o.nazwisko, o.imie1, p.pensja
INTO o_Nazwisko, o_Imie1, p_Pensja
FROM osoby o, pensje p,zatrudnienia z
1
WHERE o.plec=o_Plec and o.id=z.id_os and o.id=p.id_os and z.do is null and p.do is null
and
p.pensja=(SELECT MAX(p.pensja) FROM osoby o,zatrudnienia z, pensje p
WHERE o.plec=o_Plec and o.id=z.id_os and o.id=p.id_os and z.do is null and p.do is null);
DBMS_OUTPUT.PUT_LINE(o_Nazwisko ||' '|| o_Imie1 ||' '|| p_Pensja);
END;
2`. Napisać kod bloku animowanego w PL/SQL za pomocą którego zostanie
wyświetlony komunikat: osoba wybrana, która jest imie i nazwisko ma
inicjały Przy czym należy wykorzystać 2 zmienne PL/SQL do podstawienia
inicjałów, których typ jest zainicjowany jako podtyp typu tekstowego o
stałej długości 1. Osoba jest dana poprzez indetyfikator (id) zainicjowanie
zmiennej PL/SQL.
DECLARE
o_Id NUMBER:=1;
SUBTYPE inicjal IS CHAR(1);
o_Inic1 inicjal;
o_Inic2 inicjal;
o_Nazwisko VARCHAR(20);
o_Imie1 VARCHAR(20);
BEGIN
SELECT INITCAP(nazwisko), imie1,INITCAP(SUBSTR(nazwisko,1,1)),
SUBSTR(imie1,1,1)
INTO o_Nazwisko, o_Imie1,o_Inic1,o_Inic2
FROM osoby
WHERE id=o_Id;
DBMS_OUTPUT.PUT_LINE('Osoba wybrana,ktora jest '|| o_Nazwisko ||' '|| o_Imie1
||' ma inicjaly '||o_Inic1 ||' '|| o_Inic2);
END;
1. Napisać kod bloku animowanego w PL/SQL za pomocą którego zostaną
wyświetlone dane tej osoby, która kiedykolwiek była zatrudniona przez
najdłuższy okres czasu na wydziale, którego nazwa jest podana poprzez
zainicjowanie odpowiedniej zmiennej.
DECLARE
o_Nazwisko VARCHAR(20);
o_Imie VARCHAR(20);
w_Nazwa VARCHAR(10):='prawo';
BEGIN
SELECT o.nazwisko, o.imie
INTO o_Nazwisko, o_Imie1
From osoby o,zatrudnienia z,wydzialy w
WHERE o.id=z.id_os and w.nazwa=w_nazwa and z.id_wydz=w.id and (sysdate-z.od)=
(Select MAX(sysdate-z1.od) from osoby o1,zatrudnienia z1, wydzialy w1
where o1.id=z1.id_os and w1.nazwa=w_nazwa and z1.id_wydz=w1.id);
DBMS_OUTPUT.PUT_LINE(o_Nazwisko ||' '|| o_Imie1);
END;
2. Napisać kod bloku animowanego w PL/SQL za pomocą którego będzie można
wyświetlić nazwę tego wydziału, na którym liczba wszystkich kiedykolwiek
2
zatrudnionych osób była największa, przy czym płeć tych osób jest podana
poprzez zainicjowanie odpowiedniej zmiennej.
DECLARE
PL CHAR(1):='M';
WYNIK VARCHAR(30);
BEGIN
SELECT NAZWA INTO WYNIK FROM WYDZIALY WHERE ID =
(SELECT ID FROM (SELECT COUNT (Z.ID_WYDZ) ILE ,Z.ID_WYDZ ID
FROM ZATRUDNIENIA Z, OSOBY O
WHERE O.ID=Z.ID_OS
AND O.PLEC=PL
GROUP BY Z.ID_WYDZ)
WHERE ILE =(
SELECT MAX(ILE)
FROM(
SELECT COUNT (Z.ID_WYDZ) ILE ,Z.ID_WYDZ
FROM ZATRUDNIENIA Z, OSOBY O
WHERE O.ID=Z.ID_OS
AND O.PLEC=PL
GROUP BY Z.ID_WYDZ)));
DBMS_OUTPUT.PUT_LINE( ''||WYNIK||'');
END;
Ćwiczenia 4 (Typy rekordowe)
1a) Zdefiniować typ rekordowy t_rekordOsoba i przy jego wykorzystaniu
wyświetlić dane osoby o id poprzez zdefiniowanie odpowiedniej zmiennej
PL/SQL.
DECLARE
TYPE t_RecordOsoba IS RECORD
(
o_Id osoby.id%TYPE,
o_Nazwisko osoby.nazwisko%TYPE,
o_Imie1 osoby.imie1%TYPE,
o_Imie2 osoby.imie2%TYPE,
o_Plec osoby.plec%TYPE,
o_D osoby.d_ur%TYPE
);
osoba t_RecordOsoba;
o_Id1 NUMBER:=1;
BEGIN
SELECT o.id, o.nazwisko,o.imie1,o.imie2, o.plec,o.d_ur
INTO osoba
FROM osoby o
3
WHERE o.id=o_Id1;
DBMS_OUTPUT.PUT_LINE('Osoba o id=' || osoba.o_Id || 'to' || osoba.o_Imie1 ||' '||
osoba.o_Nazwisko || ' dacie urodzenia ' || osoba.o_d);
END;
b) wykorzystanie rekordu niejawnego
DECLARE
osoba osoby%ROWTYPE;
o_Id1 NUMBER:=1;
BEGIN
SELECT o.id, o.nazwisko,o.imie1,o.imie2, o.d_ur,o.plec
INTO osoba
FROM osoby o
WHERE o.id=o_Id1;
DBMS_OUTPUT.PUT_LINE('Osoba o id=' || osoba.id || 'to' || osoba.imie1 ||' '||
osoba.nazwisko || ' dacie urodzenia ' || osoba.d_ur);
END;
2. Zdefiniować 2 type rekordowe użytkownika t_rekordOsoba1 I t_recordOsoba2
zawierające następujące pola: z_id, z_nazwisko, z_imie, z_data_ur.
Następnie zadeklarować po 2 zmienne dla każdego z tych typów recordowych.
Niech pola jednej z tych zmiennych z_id=20, z_nazwisko=Kowalska,
z_imie=Maria, z_data_ur=23/05/1981. Dokonać próby przypisania tych wartości
pozostałym zadeklarowanych zmiennych rekordowych.
DECLARE
TYPE t_RecordOsoba1 IS RECORD
(
z_id osoby.id%TYPE,
z_nazwisko osoby.nazwisko%TYPE,
z_imie osoby.imie1%TYPE,
z_data_ur osoby.d_ur%TYPE
);
TYPE t_RecordOsoba2 IS RECORD
(
z_id osoby.id%TYPE,
z_nazwisko osoby.nazwisko%TYPE,
z_imie osoby.imie1%TYPE,
z_data_ur osoby.d_ur%TYPE
);
os1 t_RecordOsoba1;
os2 t_RecordOsoba2;
BEGIN
4
os1.z_id:=20;
os1.z_nazwisko:='Kowalska';
os1.z_imie:='Maria';
os1.z_data_ur:=TO_DATE('23/05/1981','DD/MM/YYYY');
os2.z_id:=os1.z_id;
os2.z_nazwisko:=os1.z_nazwisko;
os2.z_imie:=os1.z_imie;
os2.z_data_ur:=os1.z_data_ur;
END;
3.a) Wstawić do tabeli wiersz danych id=15, nazwisko=Pawlowska,imie1=Marta,
data_ur=06/07/1982, plec=K. Wstawienie wiersza danych do tabeli bazodanowej
przeprowadzić z wykorzystaniem zmiennej rekordowej.
DECLARE
osoba osoby%ROWTYPE;
BEGIN
osoba.id:=15;
osoba.nazwisko:='Pawlowska';
osoba.imie1:='Marta';
osoba.data_ur:=TO_DATE('06/07/1982', 'DD/MM/YYYY');
osoba.plec:='K';
INSERT INTO osoby VALUES osoba;
COMMIT;
END;
b) W punkcie a) zostały podane błędne dane ustawionego rekordu. Poprawne
dane są następujące id=15, nazwisko=Pawłowki imie=Marek data_ur=05/05/1980,
plec=M. Dokonaj korekty błędu ustawionego wiersza danych z wykorzystaniem
zmiennej rekordowej.
DECLARE
osoba osoby%ROWTYPE;
BEGIN
osoba.id:=15;
osoba.nazwisko:='Pawlowski';
osoba.imie1:='Marek';
osoba.data_ur:=TO_DATE('05/05/1980', 'DD/MM/YYYY');
osoba.plec:='M';
UPDATE osoby SET ROW=osoba WHERE id=15;
COMMIT;
END;
c) Niektóre z poprawionych danych w punkcie b) nadal są błędne osoba o id=15
ma nazwisko Pawelski I data_ur=20/07/1982 pozostałe dane są poprawne.
Dokonaj korekty błędnych danych wykorzystując w tym celu zmienną rekordową.
5
DECLARE
OS OSOBY%ROWTYPE;
BEGIN
select id, imie1,imie2,d_ur,plec into os.id,os.imie1,os.imie2,os.d_ur,os.plec
from osoby
where id=15;
os.nazwisko:='Pawelski';
update OSOBY set row=OS where id=15;
END;
Ćwiczenia 5 (if, for, while, loop)
1. Napisać kod bloku anonimowego PL/SQL, za pomocą którego dla dowolnej
osoby danej za pomocą id podanego w odpowiedniej zmiennej PL/SQL -owej
zostanie wyświetlony komunikat dotyczącej sumy jej nazwiska i mienia. I tak
gdy długość jest mniejsza od 9 "osoba o krótkiej długości imienia i
nazwiska", gdy od 10 do 20 " osoba o długiej nazwiska i imienia" , zaś
ponad 20 - "osoba o bardzo długiej długości imienia i nazwiska"
DECLARE
o_Id osoby.id%TYPE:=1;
opis VARCHAR2(60);
o_dl NUMBER(2);
BEGIN
SELECT length(o.nazwisko)+length(o.imie1)
INTO o_dl
FROM osoby o
WHERE o.id=o_Id;
IF o_dl < 9 THEN
opis:='osoba o krotkiej dlugosci imienia i nazwiska';
ELSIF o_dl > 10 AND o_dl < 20 THEN
opis:='osoba o dlugiej dlugosci imienia i nazwiska';
ELSE
opis:='osoba o bardzo dlugiej dlugosci imienia i nazwiska';
END IF;
DBMS_OUTPUT.PUT_LINE(opis);
END;
2. Napisać kod bloku anonimowego PL/SQL, za pomocą którego dla dowolnej
osoby za pomocą id podanego w odpowiednio w odpowiednio zainicjowanej
zmiennej PL/SQL - owej zostanie wyświetlony komunikat dotyczący daty jej
urodzin. Osoba o id = 1. Tj. Lis Jan urodził się w 4 kwartale. Nie wolno
stosować interwału czasowego określającego kwartał.
DECLARE
o_Id osoby.id%TYPE:=1;
opis VARChAR2(60);
o_miesiac NUMBER;
BEGIN
SELECT TO_NUMBER(TO_CHAR(d_ur,'MM'))
INTO o_miesiac
6
FROM osoby
WHERE id=o_id;
IF o_miesiac < 4 THEN
opis:='osoba o id= '||o_Id||' urodzila sie w 1 kwartale';
ELSIF o_miesiac <7 THEN
opis:='osoba o id= '||o_Id||' urodzila sie w 2 kwartale';
ELSIF o_miesiac < 10 THEN
opis:='osoba o id= '||o_Id||' urodzila sie w 3 kwartale';
ELSE
opis:='osoba o id= '||o_Id||' urodzila sie w 4 kwartale';
END IF;
DBMS_OUTPUT.PUT_LINE(opis);
END;
3. Napisać kod blok anonimowego PL/SQL, za pomocą którego dla aktualnej
osoby podaje za pomocą id podanego w odpowiednio zainicjowanej zmiennej
PL/SQL - owej zostanie wyświetlony komunikat dotyczący aktualnie pobranej
pensji - do której grupy wynagrodzeń należy pensja. Poniżej 800zl - grupa
I, od 801 do 1100 - grupa II, od 1101 do 1400zl - grupa III itd. co 300 zł.
Zaś po 2000zl co 500zl nowa grupa, zaś po 6000 zł - grupa XIII. Osoba o id
= 3 tj. Norek Tadeusz pobiera aktualnie pensje w wysokości 1800zl - V grupa
wynagrodzeń. Zastosować instrukcje CASE wyszukująca.
DECLARE
o_Id osoby.id%TYPE:=3;
p_pensja pensje.pensja%TYPE;
opis VARCHAR2(60);
BEGIN
SELECT p.pensja
INTO p_pensja
FROM osoby o, pensje p
WHERE o.id=o_Id AND p.id_os=o_Id AND p.do IS NULL;
CASE
WHEN p_pensja < 800 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa I';
WHEN p_pensja > 801 AND p_pensja < 1100 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa II';
WHEN p_pensja > 1100 and p_pensja < 1400 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa III';
WHEN p_pensja > 1401 and p_pensja < 1700 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa IV';
WHEN p_pensja >1701 and p_pensja < 2000 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa V';
WHEN p_pensja > 2001 and p_pensja < 3000 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa VI';
WHEN p_pensja > 3001 and p_pensja < 4000 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa VII';
WHEN p_pensja > 4001 and p_pensja < 5000 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa VIII';
WHEN p_pensja > 5001 and p_pensja < 6000 THEN
opis:='osoba o id='||o_Id||'pobiera pensje '||p_pensja||' - grupa IX';
7
ELSE
opis:='Nie ma aktualnej pensji ';
END CASE;
DBMS_OUTPUT.PUT_LINE(opis);
END;
4. Napisać kod bloku anonimowego PL/SQL, za pomocą którego dla dowolnej
osoby zadanej przez jej id w odpowiednio zainicjowanej PL/SQL - owej
zostanie wyświetlony odpowiedni komunikat dotyczący daty urodzenia. Osoba o
id = 1 tj. Lis Jan urodził się w październiku. Zastosować instrukcje CASE
sprawdzająca.
DECLARE
zm_id osoby.id%TYPE:=2;
zm_dane VARCHAR(40);
zm_mies NUMBER(2);
zm_miesiac VARCHAR(15);
BEGIN
SELECT imie1||' '||nazwisko, TO_NUMBER(TO_CHAR(d_ur,'mm')) INTO zm_dane,
zm_mies
FROM osoby
WHERE id=zm_id;
CASE zm_mies
WHEN 1 THEN zm_miesiac:='styczeniu';
WHEN 2 THEN zm_miesiac:='lutym';
WHEN 3 THEN zm_miesiac:='marcu';
WHEN 4 THEN zm_miesiac:='kwietniu';
WHEN 5 THEN zm_miesiac:='maju';
WHEN 6 THEN zm_miesiac:='czerwcu';
WHEN 7 THEN zm_miesiac:='lipiecu';
WHEN 8 THEN zm_miesiac:='sierpniu';
WHEN 9 THEN zm_miesiac:='wrzesniu';
WHEN 10 THEN zm_miesiac:='pazdzierniku';
WHEN 11 THEN zm_miesiac:='listopadzie';
WHEN 12 THEN zm_miesiac:='grudniu';
END CASE;
DBMS_output.put_line('osoba o id= '||zm_id||'tj. '||zm_dane||' urodzila sie w '||zm_miesiac||'');
END;
5. Napisać kod bloku anonimowego PL/SQL, za pomocą którego dla pierwszych
10 osób zostanie wyświetlony komunikat
1. Lis Jan ma inicjały L.J.
2. Kot Adam ma inicjały K.A.
.
.
.
10. Murek Danuta ma inicjały M.D.
a) zastosować pętle prosta
b) zastosować pętle WHILE
DECLARE
licznik NUMBER:=1;
8
o_in1 CHAR(1);
o_in2 CHAR(1);
o_imie osoby.imie%TYPE;
o_naz osoby.nazwisko%TYPE;
BEGIN
LOOP
SELECT nazwisko, imie1, SUBSTR(nazwisko,1,1), SUBSTR(imie1,1,1)
INTO o_imie, o_naz, o_in1, o_in2
FROM osoby
WHERE id=licznik;
EXIT WHEN licznik=10;
END LOOP;
END;
Ćwiczenia 6 (Instrukcje SQL)
1. Napisać kod bloku anonimowego PL/SQL, który umożliwia zwrot
identyfikatora wiersza danych zmodyfikowanego instrukcja DML.
W tym celu do tabeli osoby wprowadzić przykładowy wiersz danych id=12,
nazwisko='Tomczyk', imie='Monika', d_ur='21/01/1987',plec='k' i wydrukować
identyfikator wprowadzonego wiersza danych. Następnie dla wiersza danych
tabeli osoby, którego identyfikator jest równy identyfikatorem
wprowadzonego wiersza danych dodać operacje aktualizacji d_ur='12/01/1987'
pobrać nazwisko, imię, i datę urodzenia osoby aktualizowanej a następnie je
wydrukować. W końcu dokonać operacji usunięcia wiersza danych z tabeli
osoby którego identyfikator jest równy identyfikatorowi wprowadzonego
wiersza . Pobrać ten identyfikator i wydrukować go.
DECLARE
o_rowid ROWID;
o_id osoby.id%TYPE;
o_imie osoby.imie1%TYPE;
o_nazwisko osoby.nazwisko%TYPE;
o_data osoby.d_ur%TYPE;
o_plec osoby.plec%TYPE;
BEGIN
INSERT INTO osoby(id, nazwisko,imie1,imie2, d_ur, plec)
VALUES (12,'Tomczyk','Monika', NULL, TO_DATE('21/01/1987','dd/mm/yyyy'), 'K')
RETURNING rowid INTO o_rowid;
DBMS_OUTPUT.PUT_LINE('indentyfikator wstawionego wiersza' || o_rowid || ' ');
UPDATE osoby
SET d_ur=TO_DATE('12/01/1987', 'dd/mm/yyyy')
WHERE rowid=o_rowid
RETURNING nazwisko, imie1, d_ur
INTO o_nazwisko, o_imie, o_data;
DBMS_OUTPUT.PUT_LINE( ' '|| o_nazwisko || ' '||o_imie ||' '||o_data||' ');
DELETE FROM osoby
WHERE rowid=o_rowid
RETURNING rowid INTO o_rowid;
DBMS_OUTPUT.PUT_LINE( 'indentyfikator usunietego wiersza to '|| o_rowid||' ');
END;
9
2. Napisać kod bloku anonimowego PL/SQL wykorzystującego pętle numeryczna w
celu wyświetlenia z listy osób aktualnie
zatrudnionych na każdym wydziale (liczba wydziałów i osób jest dowolna)
Lista osób aktualnie zatrudniona na wydziale Fizyka
1. Norek Tadeusz
2. Kula Katarzyna
3. Murek Danuta
Lista osób aktualnie zatrudniona na wydziale Matematyka
1. Kot Adam
2. Lis Anna
3. ........
DECLARE
z_licznik1 BINARY_INTEGER:=1;
z_licznik2 BINARY_INTEGER:=1;
z_ile1 NUMBER(2);
z_ile2 NUMBER(2);
w_nazwa wydzialy.nazwa%TYPE;
o_nazwisko osoby.nazwisko%TYPE;
o_imie osoby.imie1%TYPE;
BEGIN
SELECT COUNT(id)
INTO z_ile1
FROM wydzialy;
FOR z_licznik1 IN 1..z_ile1 LOOP
SELECT nazwa
INTO w_nazwa
FROM wydzialy
WHERE id=z_licznik1;
DBMS_OUTPUT.PUT_LINE('Lista osob aktualnie zatrudnionych na wydziale '||w_nazwa
||'');
SELECT COUNT(*)
INTO z_ile2
FROM zatrudnienia;
WHERE id_wydz=z_licznik AND do IS null;
FOR z_licznik2 IN 1..z_ile2
SELECT o.imie1, o.nazwisko INTO o_imie, o_nazwisko
FROM osoby o, zatrudnienia z
WHERE o.id=z.id_os AND z.id_wydz=z_licznik And z.do is null;
DBMS_OUTPUT.PUT_LINE(''||z_licznik2||' '||o_nazwisko ||''||o_imie||' ');
END LOOP;
END LOOP;
END;
3. Napisać kod bloku anonimowego PL/SQL wykorzystującego pętle numeryczna w
celu wyświetlenia listy osób aktualnie zatrudnionych w poszczególnych
rokach i miesiącach (poczynając od aktualnego roku a kończąc na najstarszym
10
Ćwiczenia 7 (kursory)
1a) Napisać kod bloku anonimowego PL/SQL z wykorzystaniem kursora jawnego,
którego dla dowolnej osoby z tabeli osoby będzie wyświetlał komunikat:
"Osoba nazwisko i imię ma inicjały"
Wykorzystac:
* petla prosta
* petle while
DECLARE
zm_imie1 osoby.imie1%TYPE;
zm_nazwisko osoby.nazwisko%TYPE;
zm_in1 CHAR(1);
zm_in2 CHAR(1);
CURSOR k_osoby IS
SELECT imie1, INITCAP(nazwisko), SUBSTR(imie1,1,1), SUBSTR(nazwisko,1,1)
FROM osoby;
BEGIN
OPEN k_osoby;
LOOP
FETCH k_osoby INTO zm_imie1, zm_nazwisko, zm_in1,zm_in2;
EXIT WHEN k_osoby%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Osoba '||zm_imie1||' '||zm_nazwisko||' ma inicjaly '||zm_in1||'.'||
zm_in2||'. ');
END LOOP;
CLOSE k_osoby;
END;
1b)
DECLARE
zm_imie1 osoby.imie1%TYPE;
zm_nazwisko osoby.nazwisko%TYPE;
zm_in1 CHAR(1);
zm_in2 CHAR(1);
CURSOR k_osoby IS
11
SELECT imie1, INITCAP(nazwisko), SUBSTR(imie1,1,1), SUBSTR(nazwisko,1,1)
FROM osoby;
zm_dane k_osoby%ROWTYPE;
BEGIN
OPEN k_osoby;
FETCH k_osoby INTO zm_imie1, zm_nazwisko, zm_in1,zm_in2;
WHILE k_osoby%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('Osoba '||zm_imie1||' '||zm_nazwisko||' ma inicjaly '||zm_in1||'.'||
zm_in2||'. ');
FETCH k_osoby INTO zm_imie1, zm_nazwisko, zm_in1,zm_in2;
END LOOP;
CLOSE k_osoby;
END;
2 Napisać kod bloku anonimowego PL/SQL z kursorem jawnym (z blokada),
którego zadaniem jest podniesienie o 50zl aktualnej pensji osoba aktualnie
zatrudnionym, które jeszcze nie miały podwyżki. Transakcje zatwierdzić.
DECLARE
z_id osoby.id%TYPE;
CURSOR k_aktualizacja IS
SELECT o.id
FROM pensje p, zatrudnienia z, osoby o
WHERE o.id = z.id_os AND o.id = p.id_os AND z.do IS NULL AND o.id IN
(
SELECT id_os
FROM pensje
GROUP BY id_os
HAVING COUNT(*) <= 1
)
FOR UPDATE OF p.pensja;
BEGIN
OPEN k_aktualizacja;
FETCH k_aktualizacja INTO z_id;
WHILE k_aktualizacja%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(z_id);
UPDATE pensje SET pensja = pensja + 50 WHERE id_os = z_id;
FETCH k_aktualizacja INTO z_id;
END LOOP;
COMMIT;
END;
3 Mamy dokonać podwyżki pensji aktualnej pensji osobom aktualnie
zatrudnionym. Każda z tych osób ma dostać taka kwotę podwyżki, jaka wynika
z okresu jej pracy na danym wydziale za każdy przepracowany rok osoba
dostaje podwyżkę w wysokości 3% kwoty swojej aktualnej pensji. Transakcje
zatwierdzić.
DECLARE
zm_id pensje.id_os%TYPE;
zm_pensja pensje.pensja%TYPE;
CURSOR k_pensja IS
12
SELECT
z.id_os,TRUNC((MONTHS_BETWEEN(SYSDATE,p.od)/12)*0.03*p.pensja+p.pensja)
koncowa
FROM pensje p,zatrudnienia z
WHERE p.id_os=z.id_os
AND p.do IS NULL
AND z.do IS NULL;
BEGIN
OPEN k_pensja;
LOOP
FETCH k_pensja INTO zm_id, zm_pensja;
EXIT WHEN k_pensja%NOTFOUND;
UPDATE pensje SET pensja=zm_pensja WHERE id_os=zm_id;
END LOOP;
CLOSE k_pensja;
COMMIT;
END;
Ćwiczenia 8 (obsługa wyjątków)
1. Zaprojektować blok w którym w jego części wykonawczej zmiennej
z_nazwisko typu VARCHAR(10) przypisano wartość 'Nowak-Konopacka'.
Zaprojektować obsługę tego błędu za pomocą wyjątku predefiniowanego, przy
czym obsługa błędu polega na wyświetleniu komunikatu:"Zbyt długi ciąg
znaków alfanumerycznych"
DECLARE
z_nazwisko VARCHAR2(10);
BEGIN
z_nazwisko:='Nowak-Konopacka';
EXCEPTION
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE ('Zbyt dlugi ciag znakow alfanumerycznych');
END;
2. Zaprojektować blok PL/SQL z kursorem niejawnym którego zadaniem jest
wyświetlanie osób aktualnie zatrudnionych i liczbę pełnych przepracowanych
lat w danym miejscu zatrudnienia, przy czym należy wyświetlić te osoby
których liczba lat jest większa (mniejsza) niż liczba podawana w pewnej
zmiennej. Zaprojektować obsługę wyjątków poprzez wyjątki predefiniowane
które wyłapią wszystkie możliwe błędy i wyświetla odpowiednie komentarze.
Dodatkowo zaprojektować poprzez wyjątek predefiniowany obsługę dowolnego
błędu.
DECLARE
z_liczba NUMBER:=10;
z_imie osoby.imie1%TYPE;
z_nazwisko osoby.nazwisko%TYPE;
z_lata NUMBER;
BEGIN
SELECT o.imie1, o.nazwisko,TRUNC((MONTHS_BETWEEN(SYSDATE, z.od))/12)
13
INTO z_imie,z_nazwisko,z_lata
FROM zatrudnienia z, osoby o
WHERE o.id=z.id_os AND z.do IS NULL AND
TRUNC((MONTHS_BETWEEN(SYSDATE, z.od))/12) > z_liczba;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('nie znaleziono danych');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('za duzo danych');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('inny blad');
END;
3. Do bazy danych został‚a wprowadzona osoba o id=11, której dane zostały
wprowadzone blednie. Należy zaprojektować obsługę wyjątków, która wyłapie
wszystkie te błędy i wyświetli komentarze:
a)Data urodzenia jest późniejsza niż data zatrudnienia!
b)Data zatrudnienia jest późniejsza niż data zwolnienia!
c)Data urodzenia jest późniejsza niż data zatrudnienia i data zatrudnienia
jest późniejsza niż data zwolnienia!
DECLARE
z_id osoby.id%TYPE:=11;
z_data_zat zatrudnienia.od%TYPE:='23/11/1999';
z_data_zwol zatrudnienia.do%TYPE:='21/02/1989';
z_data_ur osoby.d_ur%TYPE:='12/06/1970';
wyjatek1 EXCEPTION;
wyjatek2 EXCEPTION;
wyjatek3 EXCEPTION;
BEGIN
INSERT INTO osoby(id, nazwisko,imie1,imie2, d_ur, plec)
VALUES (11,'Nowak','Monika', NULL, TO_DATE('z_data_ur','DD/MM/YYYY'),'K');
INSERT INTo zatrudnienia(id,id_os, od,do,id_wydz)
VALUES
(11,11,TO_DATE('z_data_zat','DD/MM/YYYY'),TO_DATE('z_data_zwol','DD/MM/YYYY'
),2);
IF z_data_ur > z_data_zat THEN
RAISE wyjatek1;
ELSIF z_data_zat > z_data_zwol THEN
RAISE wyjatek2;
ELSIF z_data_ur > z_data_zat AND z_data_zat > z_data_zwol THEN
RAISE wyjatek3;
END IF;
EXCEPTION
WHEN wyjatek1 THEN
DBMS_OUTPUT.PUT_LINE('data urodzenia jest pozniejsza niz data
zatrudnienia');
WHEN wyjatek2 THEN
14
DBMS_OUTPUT.PUT_LINE('data zatrudnienia jest pozniejsza niz data
zwolnienia ');
WHEN wyjatek3 THEN
DBMS_OUTPUT.PUT_LINE('data urodzenia jest pozniejsza niz data
zatrudnienia i data zatrudnienia jest pozniejsza niz
data zwolnienia ');
END;
4. Zaprojektować‡ blok PL/SQL-owy z kursorem niejawnym którego zadaniem
jest wyświetlenie id osoby i jej inicjałów osób, które mają drugie imię.
Zaprojektować obsługę wyjątków. Za pomocą wyjątku predefiniowanego, który
obsługuje dowolny błąd. Obsługa polega na wpisaniu do tabeli tabela_bledow
kodu wykrytego błędu i przypisanego mu komentarza (max. 200 znaków
długości).
DECLARE
osoba osoby%ROWTYPE;
in1 CHAR(1);
in2 CHAR(1);
komentarz VARCHAR(200);
BEGIN
SELECT id, nazwisko, imie1, imie2, d_ur, plec, SUBSTR(nazwisko,1,1),
SUBSTR(imie1,1,1)
INTO osoba, in1,in2
FROM osoby
WHERE imie2 IS NOT NULL;
DBMS_OUTPUT.PUT_LINE('dane osoby: '|| id.osoba||' '||imie1.osoba||' '||imie2.osoba||' '||
nazwisko.osoba||' '||
d_ur.osoba||' '||plec.osoba ||' inicjaly: ' ||in1||' '||in2);
EXCEPTION
WHEN NO_DATA_FOUND THEN
komentarz:='Nie znaleziono danych';
INSERT INTO tab_bledow
VALUES(-1403,komentarz);
WHEN TOO_MANY_ROWS THEN
komentarz:='za duzo danych';
INSERT INTO tab_bledow
VALUES(-1422,komentarz);
WHEN OTHERS THEN
komentarz:='inny blad';
INSERT INTO tab_bledow
VALUES(0,komentarz);
END;
5. W zadaniu z pętlami numerycznymi FOR, które umożliwiały w poszczególnych
latach i ich miesiącach wyświetlenie liczby, zatrudnionych osób tak
zaprojektować obsługę wyjątków, aby wyświetliły również te lata i ich
miesiące, w których nikogo nie zatrudniono (tj. z lista zatrudnionych osób)
15
Ćwiczenia 9 (podprogramy: procedury, funkcje)
1. Zaprojektować procedurę, które umożliwi wprowadzanie danych osoby do
tabeli osoby. Należy przy tym zaprojektować obsługę błędów wprowadzono do
tabeli osoby danych osoby już wprowadzonej.
CREATE OR REPLACE PROCEDURE nowa
(i_id IN osoby.id%TYPE,
i_nazwisko IN osoby.nazwisko%TYPE,
i_imie1 IN osoby.imie1%TYPE,
i_imie2 IN osoby.imie2%TYPE,
i_d_ur IN osoby.d_ur%TYPE,
i_plec IN osoby.plec%TYPE)
AS
BEGIN
INSERT INTO osoby(id, nazwisko, imie1, imie2, d_ur, plec)
VALUES(i_id, i_nazwisko, i_imie1, i_imie2, i_d_ur, i_plec);
DBMS_OUTPUT.PUT_LINE('Dane zostaly wprowadzone!');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('Taka osoba juz istnieje!');
END nowa;
EXECUTE nowa (20, 'Kowalski', 'Jan', 'Janek', TO_DATE('13/10/1985','dd/mm/yyyy'), 'm');
2.Zaprojektowac procedurę i funkcje w języku PL/SQL, która umożliwia
obliczenie osób danej płci w tabeli osoby. Następnie wywołać podprogramy
PL/SQL. W środowisku SQL i wynik wydrukować.
CREATE OR REPLACE PROCEDURE liczOsoby(
z_plec osoby.plec%TYPE)
AS
liczba NUMBER;
BEGIN
SELECT count(id) ilosc
INTO liczba
FROM osoby
WHERE plec=z_plec;
--RAISE APPLICATION_ERROR(liczba,'Liczba osob');
END liczOsoby;
BEGIN
liczOsoby('K');
END;
CREATE OR REPLACE FUNCTION liczbaOsob
( z_plec osoby.plec%TYPE )
16
RETURN NUMBER IS
liczba NUMBER;
BEGIN
SELECT count(id) ilosc
INTO liczba
FROM osoby
WHERE plec=z_plec;
RETURN liczba;
END liczbaOsob;
DECLARE
z_plec osoby.plec%TYPE:='M';
liczba NUMBER;
BEGIN
liczba:=liczbaOsob(z_plec);
DBMS_OUTPUT.PUT_LINE('Liczba osob o danej plci '||z_plec||' wynosi '||liczba);
END;
3. Zaprojektować funkcje PL/SQL, która dla danego wydziału poda informacje
o procencie osób aktualnie zatrudnionych osób na nim w stosunku do liczby
wszystkich osób aktualnie zatrudnionych w następujący sposób:
"Wydział zatrudnia ponad 50% ogółu zatrudnionych" lub
"Wydział zatrudnia ponad 25% ogółu zatrudnionych" lub
"Wydział zatrudnia poniżej 25% ogółu zatrudnionych" lub
"Na wydziale nikt nie jest zatrudniony"
zastosować konstrukcje bloku funkcyjnego z więcej niż jedna instrukcja
RETURN. Drukowanie wyniku działania funkcji w bloku. Wyniki wydrukować dla
wszystkich wydziałów.
CREATE OR REPLACE FUNCTION l_zatrudnionych
(z_wydzial wydzialy.nazwa%TYPE)
RETURN VARCHAR2 IS
l_wydz NUMBER;
l_wszyscy NUMBER;
BEGIN
SELECT count(o.id) ilosc
INTO l_wszyscy
FROM osoby o, zatrudnienia z
WHERE o.id=z.id_os AND z.do IS NULL;
SELECT count(o.id) ilosc
INTO l_wydz
FROM osoby o, zatrudnienia z,wydzialy w
WHERE o.id=z.id_os AND z.do IS NULL AND z.id_wydz=w.id AND w.nazwa=z_wydzial;
IF (l_wydz/l_wszyscy)*100 >= 50 THEN
RETURN 'Wydzial zatrudnia ponad 50% ogolu zatrudnionych';
ELSIF (l_wydz/l_wszyscy)*100 BETWEEN 25 AND 50 THEN
RETURN 'Wydzial zatrudnia ponad 25% ogolu zatrudnionych';
ELSIF (l_wydz/l_wszyscy)*100 BETWEEN 0 AND 25 THEN
17
RETURN 'Wydzial zatrudnia ponizej 25% ogolu zatrudnionych';
END IF;
END l_zatrudnionych;
DECLARE
z_wydzial wydzialy.nazwa%TYPE:='fizyka';
komentarz VARCHAR2(100);
BEGIN
komentarz:=l_zatrudnionych(z_wydzial);
DBMS_OUTPUT.PUT_LINE(z_wydzial ||' '|| komentarz);
z_wydzial:='matematyka';
komentarz:=l_zatrudnionych(z_wydzial);
DBMS_OUTPUT.PUT_LINE(z_wydzial ||' '|| komentarz);
z_wydzial:='prawo';
komentarz:=l_zatrudnionych(z_wydzial);
DBMS_OUTPUT.PUT_LINE(z_wydzial ||' '|| komentarz);
END;
4. Zaprojektować procedurę zwracającą wartość największej pensji osoby
aktualnie zatrudnionej której wypłacanie rozpoczęto w podanym roku. Ponadto
procedura ma zwracać wartość największej aktualnie wypłacanej pensji osobie
aktualnie zatrudnionej. Obie wartości wydrukować w bloku wywołania.
CREATE OR REPLACE PROCEDURE pensja
( z_rok NUMBER )
AS
z_pensja pensje.pensja%TYPE;
z_naj_pensja pensje.pensja%TYPE;
BEGIN
SELECT MAX(p.pensja) pensja
INTO z_pensja
FROM pensje p, osoby o, zatrudnienia z
WHERE o.id=p.id_os AND o.id=z.id_os AND z.do IS NULL AND p.do IS NULL
AND TO_NUMBER(TO_CHAR(p.od,'YYYY'))=z_rok;
SELECT MAX(p.pensja) pensja
INTO z_naj_pensja
FROM pensje p, osoby o, zatrudnienia z
WHERE o.id=p.id_os AND o.id=z.id_os AND z.do IS NULL AND p.do IS NULL;
DBMS_OUTPUT.PUT_LINE(z_pensja ||' '|| z_naj_pensja);
END pensja;
BEGIN
pensja(1999);
END;
18
Ćwiczenia 10 (pakiety)
1. Mamy zaprojektować pakiet zawierający (globalnie) dostępne: procedurę
wprowadzanie danych nowej osoby do tabeli osoby, procedurę usuwania danych
osoby już wprowadzonej do tabeli, przy czym musi ona zawierać obsługę
deklarowanego przez użytkownika błędu nie znalezienia rekordu do usunięcia,
procedurę ( z pętlą prostą) wyświetlającą listę aktualnie zatrudnionych
osób a wydziale wskazanym przez swoją nazwę oraz błąd użytkownika
w_osobaNieznaleziona.
CREATE OR REPLACE PACKAGE osoba AS
PROCEDURE dodajOsobe
(
z_id osoby.id%TYPE,
z_nazwisko osoby.nazwisko%TYPE,
z_imie1 osoby.imie1%TYPE,
z_imie2 osoby.imie2%TYPE,
z_data osoby.d_ur%TYPE,
z_plec osoby.plec%TYPE
);
PROCEDURE usunOsobe
(
z_id osoby.id%TYPE);
w_osobaNieznaleziona EXCEPTION;
PROCEDURE zatrudnieni
(
z_wydzial wydzialy.nazwa%TYPE );
END osoba;
--------------------------------------------------------------------------CREATE OR REPLACE PACKAGE BODY osoba AS
PROCEDURE dodajOsobe
(
z_id osoby.id%TYPE,
z_nazwisko osoby.nazwisko%TYPE,
z_imie1 osoby.imie1%TYPE,
z_imie2 osoby.imie2%TYPE,
z_data osoby.d_ur%TYPE,
z_plec osoby.plec%TYPE
)
AS
BEGIN
INSERT INTO osoby(id,nazwisko,imie1,imie2,d_ur,plec)
VALUES(z_id,z_nazwisko,z_imie1,z_imie2,z_data,z_plec);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('Osoba o podanym id juz istnieje w bazie!');
WHEN OTHERS THEN
19
DBMS_OUTPUT.PUT_LINE('Inny blad!');
END dodajOsobe;
PROCEDURE usunOsobe
(
z_id osoby.id%TYPE)
AS
w_osobaNieznaleziona EXCEPTION;
BEGIN
DELETE FROM osoby
WHERE id=z_id;
IF SQL%NOTFOUND THEN
RAISE w_osobaNieznaleziona;
END IF;
EXCEPTION
WHEN w_osobaNieznaleziona THEN
DBMS_OUTPUT.PUT_LINE('Osoby o podanym id nie znaleziono w tabeli');
END usunOsobe;
PROCEDURE zatrudnieni
(z_wydzial wydzialy.nazwa%TYPE )
AS
z_nazwisko osoby.nazwisko%TYPE;
z_imie1 osoby.imie1%TYPE;
CURSOR k_osoby IS
SELECT o.nazwisko, o.imie1
FROM osoby o,wydzialy w, zatrudnienia z
WHERE o.id=z.id_os AND z.id_wydz=w.id AND z.do IS NULL AND w.nazwa=z_wydzial;
BEGIN
OPEN k_osoby;
LOOP
FETCH k_osoby INTO z_nazwisko, z_imie1;
EXIT WHEN k_osoby%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(''||z_imie1||' '||z_nazwisko||'');
END LOOP;
CLOSE k_osoby;
END zatrudnieni;
END osoba;
20