Bazy danych - Politechnika Gdańska

Transkrypt

Bazy danych - Politechnika Gdańska
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
Instrukcja do laboratorium z przedmiotu:
Bazy danych
Laboratorium nr 3.
Metody zarządzania i analizy danych
Opracował A. Bujnowski
2010-03-08
Projekt „Przygotowanie i realizacja kierunku inżynieria biomedyczna – studia międzywydziałowe”
współfinansowany ze środków Unii Europejskiej w ramach Europejskiego Funduszu Społecznego.
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
1. Cele laboratorium – zapoznanie się z metodami wprowadzania, usuwania i modyfikacji
danych. Instrukcje warunkowe. Zapytania złożone i funkcje agregacji
2. Przykładowa baza danych:
Jako przykład bazy danych posłuży nam przygotowana uprzednio i nieco zmodyfikowana
struktura bazy dla wypożyczalni płyt DVD. Na potrzeby dzisiejszego laboratorium do
poprzednio zaprojektowanej struktury tabel dołączymy jeszcze jedną: gatunek oraz
dodamy atrybut cena dla każdej płyty. Zakładamy, że płyta należy do jednego gatunku. Kod
w języku SQL zakładający bazę danych podana jest poniżej, wytłuszczonym drukiem
pokazano zmiany w stosunku do poprzedniej wersji
CREATE TABLE klient (
imie varchar(20) not null,
nazwisko varchar(40) not null,
nr_dowodu char(10),
id_klienta serial primary key);
CREATE TABLE gatunek(
nazwa varchar(30) not null,
id_gatunku serial PRIMARY KEY
);
CREATE TABLE plyta(
tytul varchar(40) not null,
numer serial primary key,
cena numeric(4,2),
gatunek integer REFERENCES gatunek ON DELETE SET NULL ON
UPDATE CASCADE);
CREATE TABLE wypozyczenie(
kto_wypozyczyl int not null REFERENCES klient ON DELETE
RESTRICT ON UPDATE RESTRICT,
2
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
co_wypozyczyl int not null REFERENCES plyta ON DELETE
RESTRICT ON UPDATE CASCADE,
data_wypozyczenia timestamp default noow(),
data_zwrotu timestamp,
primary key(kto_wypozyczyl, co_wypozyczyl,
data_wypozyczenia) );
CREATE TABLE jest_pracownikiem(
rabat int,
id_klienta int primary key references klient);
Dla ujednolicenia sposobu pracy w tym ćwiczeniu, po zalogowaniu do serwera
bazy.eti.pg.gda.pl usuń poprzednią bazę poleceniem:
dropdb
lab2_login
gdzie login to Twój login do systemu. Następnie załóż nową bazę o nazwie jak poprzednio
poleceniem:
createdb lab2_login
Teraz przygotuj plik tekstowy z definicją poleceń zakładających bazę danych:
mcedit baza3.sql
Wypełnij zawartość tego pliku
Połącz się ze swoją bazą danych:
poleceniami
z
zaprezentowanego
listingu.
psql lab2_login
Wczytaj instrukcje z pliku baza1.sql:
\i baza3.sql
lab2_bujnows=# \i baza3.sql
psql:baza3.sql:5: NOTICE:
CREATE TABLE will create implicit sequence
"klient_id_klienta_seq" for "serial" column "klient.id_klienta"
psql:baza3.sql:5: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index
"klient_pkey" for table "klient"
CREATE TABLE
psql:baza3.sql:9: NOTICE:
CREATE TABLE will create implicit sequence
"plyta_numer_seq" for "serial" column "plyta.numer"
psql:baza3.sql:9: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index
"plyta_pkey" for table "plyta"
CREATE TABLE
psql:baza3.sql:12: ERROR: syntax error at or near "cena" at character 2
3
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
psql:baza3.sql:19: NOTICE:
CREATE TABLE / PRIMARY KEY will create
index "wypozyczenie_pkey" for table "wypozyczenie"
CREATE TABLE
psql:baza3.sql:23: NOTICE:
CREATE TABLE / PRIMARY KEY will create
index "jest_pracownikiem_pkey" for table "jest_pracownikiem"
CREATE TABLE
psql:baza3.sql:28: NOTICE:
CREATE TABLE will create implicit
"gatunek_id_gatunku_seq" for "serial" column "gatunek.id_gatunku"
psql:baza3.sql:28: NOTICE:
CREATE TABLE / PRIMARY KEY will create
index "gatunek_pkey" for table "gatunek"
CREATE TABLE
lab2_bujnows=#
implicit
implicit
sequence
implicit
W tej chwili struktura Twojej bazy danych jest gotowa do pracy. Na początku poznamy kilka
poleceń na uzupełnienie jej danymi. Na początku jednak sprawdź, czy twój baza
przechowuje właściwą strukturę tabel:
\d
List of relations
Schema |
Name
|
Type
| Owner
--------+------------------------+----------+--------public | gatunek
| table
| bujnows
public | gatunek_id_gatunku_seq | sequence | bujnows
public | jest_pracownikiem
| table
| bujnows
public | klient
| table
| bujnows
public | klient_id_klienta_seq | sequence | bujnows
public | plyta
| table
| bujnows
public | plyta_numer_seq
| sequence | bujnows
public | wypozyczenie
| table
| bujnows
(8 rows)
\d klient
Table "public.klient"
Column
|
Type
|
Modifiers
------------+----------------------+---------------------------------------------------------------imie
| character varying(20) | not null
nazwisko
| character varying(40) | not null
nr_dowodu | character(10)
|
id_klienta | integer
| not null default
nextval('public.klient_id_klienta_seq'::text)
Indexes:
"klient_pkey" primary key, btree (id_klienta)
\d plyta
Table "public.plyta"
Column |
Type
|
Modifiers
---------+----------------------+---------------------------------------------------------tytul
| character varying(40) | not null
numer
| integer
| not null
nextval('public.plyta_numer_seq'::text)
cena
| numeric(4,2)
|
gatunek | integer
|
Indexes:
4
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
default
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
"plyta_pkey" primary key, btree (numer)
Foreign-key constraints:
"$1" FOREIGN KEY (gatunek) REFERENCES gatunek(id_gatunku)
\d gatunek
Table "public.gatunek"
Column
|
Type
|
Modifiers
------------+----------------------+----------------------------------------------------------------nazwa
| character varying(30) | not null
id_gatunku | integer
| not null default
nextval('public.gatunek_id_gatunku_seq'::text)
Indexes:
"gatunek_pkey"
primary
key,
btree
(id_gatunku)
\d jest_pracownikiem
Table "public.jest_pracownikiem"
Column
| Type
| Modifiers
------------+---------+----------rabat
| integer |
id_klienta | integer | not null
Indexes:
"jest_pracownikiem_pkey" primary key, btree (id_klienta)
Foreign-key constraints:
"$1" FOREIGN KEY (id_klienta) REFERENCES klient(id_klienta)
\d wypozyczenie
Table "public.wypozyczenie"
Column
|
Type
|
Modifiers
----------------+-----------------------------+-----------------------kto_wypozyczyl | integer
| not null
co_wypozyczyl | integer
| not null
d_wypozyczenia | timestamp without time zone | not null default now()
d_zwrotu
| timestamp without time zone |
Indexes:
"wypozyczenie_pkey" primary key, btree (kto_wypozyczyl, co_wypozyczyl,
d_wypozyczenia)
Foreign-key constraints:
"$1" FOREIGN KEY (kto_wypozyczyl) REFERENCES klient(id_klienta) ON UPDATE
RESTRICT ON DELETE RESTRICT
"$2" FOREIGN KEY (co_wypozyczyl) REFERENCES plyta(numer) ON UPDATE CASCADE
ON DELETE RESTRICT
lab2_bujnows=#
Jeżeli którakolwiek z tabel nie została założona lub jej struktura (poza właścicielem tabeli owner) jest inna niż ta, pokazana w instrukcji dokonaj niezbędnych poprawek. Może się
przydać polecenie DROP TABLE lub ALTER TABLE.
3. Wstawianie danych do tabel.
Na poprzednich zajęciach wprowadzone instrukcja wprowadzania danych do bazy danych
5
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
INSERT INTO tabela VALUES. Sprawdźmy jeszcze raz jak zadziałają poniższe instrukcje:
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
VALUES
('Jan','Kowalski','DB230398');
Sprawdź również uproszczoną metodę wprowadzania danych do takiej tabeli:
INSERT INTO klient VALUES ('Anna','Nowak');
INSERT INTO klient VALUES ('Ewa','Zielińska','DB232343');
Możliwe jest też dodawanie z wymuszeniem własnej wartości id_klienta – ale jest to
niezalecane. Sprawdź dlaczego. Odpowiedzią niech będzie poniższy fragment kodu:
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu,id_klienta)
VALUES ('Jan','Kowal','DB130398',1);
Powyższe zapytanie nie powiedzie się, gdyż próbujemy użyć istniejącego id_klienta
ponownie.
lab2_bujnows=# INSERT INTO klient (imie,nazwisko,nr_dowodu,id_klienta)
VALUES ('Jan','Kowal','DB130398',1);
ERROR:
duplicate key violates unique constraint "klient_pkey"
Ale możemy poprawnie dodać klienta, z innym id_klienta niż już użyte:
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu,id_klienta)
VALUES ('Janusz','Kowalski','DB210398',4);
lab2_bujnows=# INSERT INTO klient (imie,nazwisko,nr_dowodu,id_klienta) VALUES
('Janusz','Kowalski','DB210398',4);
INSERT 80519487 1
Problem pojawi się przy próbie dodania nowego klienta z automatycznym id_klienta:
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Maria','Kowalska','DB230300');
lab2_bujnows=#
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Maria','Kowalska','DB230300');
ERROR: duplicate key violates unique constraint "klient_pkey"
lab2_bujnows=# select * from klient;
imie | nazwisko | nr_dowodu | id_klienta
--------+-----------+------------+-----------Jan
| Kowalski | DB230398
|
1
Anna
| Nowak
|
|
2
Ewa
| Zielińska | DB232343
|
3
Janusz | Kowalski | DB210398
|
4
(4 rows)
lab2_bujnows=#
6
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
VALUES
VALUES
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
Ale w tym przypadku ponowne wykonanie tego samego polecenia już zadziała poprawnie (bo
system przyjmie id_klienta jako 5):
lab2_bujnows=#
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Maria','Kowalska','DB230300');
INSERT 80519489 1
lab2_bujnows=# select * from klient;
imie | nazwisko | nr_dowodu | id_klienta
--------+-----------+------------+-----------Jan
| Kowalski | DB230398
|
1
Anna
| Nowak
|
|
2
Ewa
| Zielińska | DB232343
|
3
Janusz | Kowalski | DB210398
|
4
Maria | Kowalska | DB230300
|
5
(5 rows)
VALUES
lab2_bujnows=#
Dlatego należy zachowywać ostrożność przy wpisywaniu wartości do kolumn o typie serial lub
auto_increment (MySQL).
W przypadku konieczności załadowania do bazy danych większej ilości danych przydatne może być
wykorzystanie skryptów podobnych do tych, które wykorzystywane były przy zakładaniu bazy
danych.
Opuść bazę danych (polecenie \q) i wyedytuj plik tekstowy jak załączono poniżej:
mcedit klienci.sql
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Adam','Wisniak','AFF456432');
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Adrian','Wicki','AFF456433');
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Iwona','Wisniak','AFF456434');
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Jolanta','Ponicka','AFF456452');
INSERT
INTO
klient
(imie,nazwisko,nr_dowodu)
('Adam','Brzeski','AFG456432');
INSERT
INTO
klient(imie,nazwisko,nr_dowodu)
('Adam','Irenowski','AFF400432');
INSERT
INTO
klient(imie,nazwisko,nr_dowodu)
('Jolanta','Wisniak','AFF454432');
Zapisz plik (F2) i opuść edytor (F10). Połącz się ze swoją bazą:
psql lab2_login
Wczytaj skrypt zewnętrzny poleceniem
7
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
\i klienci.sql.
lab2_bujnows=# \i klienci.sql
INSERT 80519490 1
INSERT 80519491 1
INSERT 80519492 1
INSERT 80519493 1
INSERT 80519494 1
INSERT 80519495 1
INSERT 80519496 1
lab2_bujnows=# select * from klient;
imie
| nazwisko | nr_dowodu | id_klienta
---------+-----------+------------+-----------Jan
| Kowalski | DB230398
|
1
Anna
| Nowak
|
|
2
Ewa
| Zielińska | DB232343
|
3
Janusz | Kowalski | DB210398
|
4
Maria
| Kowalska | DB230300
|
5
Adam
| Wisniak
| AFF456432 |
6
Adrian | Wicki
| AFF456433 |
7
Iwona
| Wisniak
| AFF456434 |
8
Jolanta | Ponicka
| AFF456452 |
9
Adam
| Brzeski
| AFG456432 |
10
Adam
| Irenowski | AFF400432 |
11
Jolanta | Wisniak
| AFF454432 |
12
(12 rows)
lab2_bujnows=#
Jak widać możliwe jest stosunkowo szybkie wczytywanie takich danych. Czasami jednak
problematyczne może okazać się wyświetlanie potwierdzeń wczytywanych danych, lub
konieczność przygotowania pliku z kompletną składnią w SQL-u. Większość systemów zarządzania
bazami danych przychodzi tutaj z pomocą udostępniając interfejs do pobierania danych z pliku.
Plik powinien być jednak odpowiednio sformatowany. W PostgreSQL poleceniem takim jest \copy:
\h COPY
Command:
COPY
Description: copy data between a file and a table
Syntax:
COPY tablename [ ( column [, ...] ) ]
FROM { 'filename' | STDIN }
[ [ WITH ]
[ BINARY ]
[ OIDS ]
[ DELIMITER [ AS ] 'delimiter' ]
[ NULL [ AS ] 'null string' ] ]
COPY tablename [ ( column [, ...] ) ]
TO { 'filename' | STDOUT }
[ [ WITH ]
[ BINARY ]
[ OIDS ]
[ DELIMITER [ AS ] 'delimiter' ]
8
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
[ NULL [ AS ] 'null string' ] ]
Copy działa jak widać w obie strony – pozwala na eksport danych z tabeli do pliku (COPY
TO) i z pliku do tabeli (COPY FROM). W tej chwili zajmiemy się tylko importem danych do
bazy danych.
Plik, który zawiera dane do wgrania powinien być odpowiednio przygotowany. Wgrywając
dane do tabeli musi on składać się z wierszy, z których każde pole zawiera dokładnie taką
samą ilość separatorów pól. Dwa kolejne separatory pól oznaczają wartość typu NULL.
Ostatnia linia nie może składać się z pustych znaków itd. Domyślnym separatorem pól jest
znak tabulacji, zaś wierszy – znak końca linii. Przygotujmy zatem kilka plików wsadowych
do wypełnienia gatunków i płyt:
W tym celu opuść bazę danych (\q) i przygotuj pliki:
mcedit gatunki.txt
Zawartość pliku:
komedia
dramat
musical
kreskówka
thriller
sensacyjny
przygodowy
historyczny
fantasy
mcedit plyty.txt
Zawartość pliku:
Shrek
15
Piraci z Karaibów
20
Calineczka
15
Szeregowiec Dolot
10
Constantine
20
Hellboy
15
UWAGA ! Ważne jest aby w pliku plyty.txt pomiędzy tytułem a ceną cisnąć TAB a nie kilka
spacji !!!
Teraz spróbuj wczytać tak przygotowane dane z pliku.
lab2_bujnows=# \copy gatunek(nazwa) from gatunki.txt
\.
lab2_bujnows=# select * from gatunek;
nazwa
| id_gatunku
-------------+-----------komedia
|
1
dramat
|
2
musical
|
3
kreskówka
|
4
thriller
|
5
sensacyjny |
6
przygodowy |
7
9
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
historyczny |
fantasy
|
(8 rows)
8
9
lab2_bujnows=#
lab2_bujnows=# \copy plyta(tytul,cena) from plyty.txt
\.
lab2_bujnows=# select * from plyta;
tytul
| numer | cena | gatunek
-------------------+-------+-------+--------Shrek
|
1 | 15.00 |
Piraci z Karaibów |
2 | 20.00 |
Calineczka
|
3 | 15.00 |
Szeregowiec Dolot |
4 | 10.00 |
Constantine
|
5 | 20.00 |
Hellboy
|
6 | 15.00 |
(6 rows)
lab2_bujnows=#
4. Aktualizacja danych w tabeli.
W tak przygotowanej bazie danych pojawili się klienci, płyty i gatunki.
lab2_bujnows=# select * from klient;
imie
| nazwisko | nr_dowodu | id_klienta
---------+-----------+------------+-----------Jan
| Kowalski | DB230398
|
1
Anna
| Nowak
|
|
2
Ewa
| Zielińska | DB232343
|
3
Janusz | Kowalski | DB210398
|
4
Maria
| Kowalska | DB230300
|
5
Adam
| Wisniak
| AFF456432 |
6
Adrian | Wicki
| AFF456433 |
7
Iwona
| Wisniak
| AFF456434 |
8
Jolanta | Ponicka
| AFF456452 |
9
Adam
| Brzeski
| AFG456432 |
10
Adam
| Irenowski | AFF400432 |
11
Jolanta | Wisniak
| AFF454432 |
12
(12 rows)
lab2_bujnows=# select * from plyta;
tytul
| numer | cena | gatunek
-------------------+-------+-------+--------Shrek
|
1 | 15.00 |
Piraci z Karaibów |
2 | 20.00 |
Calineczka
|
3 | 15.00 |
Szeregowiec Dolot |
4 | 10.00 |
Constantine
|
5 | 20.00 |
Hellboy
|
6 | 15.00 |
(6 rows)
lab2_bujnows=# select * from gatunek;
nazwa
| id_gatunku
-------------+-----------komedia
|
1
dramat
|
2
10
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
musical
kreskówka
thriller
sensacyjny
przygodowy
historyczny
fantasy
(9 rows)
|
|
|
|
|
|
|
3
4
5
6
7
8
9
lab2_bujnows=#
Płyty nie osiadają przypisanych gatunków. Spróbujmy zatem przypisać gatunki do płyt.
Dokonamy tego przy pomocy polecenia UPDATE.
Ustawmy zatem gatunek „komedia” dla płyty „Shrek”. To co trzeba zrobić to sprawdzić id
gatunku dla komedii i wpisać to do bazy danych:
lab2_bujnows=# select * from gatunek;
nazwa
| id_gatunku
-------------+-----------komedia
|
1
dramat
|
2
musical
|
3
kreskówka
|
4
thriller
|
5
sensacyjny |
6
przygodowy |
7
historyczny |
8
fantasy
|
9
(9 rows)
lab2_bujnows=# select * from gatunek where nazwa='komedia';
nazwa | id_gatunku
---------+-----------komedia |
1
(1 row)
lab2_bujnows=# update plyta set gatunek=1 where tytul='Shrek';
UPDATE 1
lab2_bujnows=# select * from plyta;
tytul
| numer | cena | gatunek
-------------------+-------+-------+--------Piraci z Karaibów |
2 | 20.00 |
Calineczka
|
3 | 15.00 |
Szeregowiec Dolot |
4 | 10.00 |
Constantine
|
5 | 20.00 |
Hellboy
|
6 | 15.00 |
Shrek
|
1 | 15.00 |
1
(6 rows)
lab2_bujnows=#
Aby wykonać to zadanie musieliśmy wykonać dwa zapytania – w pierwszym (SELECT) należało
sprawdzić id_gatunku dla komedii i drugie polecenie jest faktycznym uzupełnieniem danych
(UPDATE). Można zapisać to przy pomocy pojedynczego zapytania. Sprawdźmy to:
11
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
update plyta set gatunek=(select id_gatunki
'kreskówka') where tytul = 'Calineczka';
from
gatunek
where
nazwa
=
W podobny sposób przypisz wszystkie filmy do gatunków:
Piraci z Karaibów – przygodowy
Szeregowiec Dolot – kreskówka
Constantine - thriller
Hellboy - fantasy
Zastanów się czy w podobny sposób nie da się zapisać wypożyczeń.
Spróbuj zapisać akcję wypożyczenia płyty o tytule Constantine dla pana Jana Kowalskiego.
W podobny sposób wypożycz płyty użytkownikom:
Adrian Wicki
Iwona Wisniak
Jolanta Ponicka
:
:
:
Hellboy
Szeregowiec Dolot
Constantine
Operatory w SQL
W języku SQL istnieje szereg operatorów warunkowych do używania z klauzulą WHERE. Są to:
Operatory logiczne AND i OR , używane do połączenia warunków.
Przykład :
SELECT * FROM klient where id_klienta > 5 AND id_klienta < 10;
Operatory porównania:
> (większe), < (mniejsze) , <= (mniejsze lub równe), >= (większe lub równe), <> (różne)
W przypadku ciągów tekstowych można wyróżnić operator LIKE, który pozwala na używanie
znaków typu wildcard. Znaki te to '_' - zastępuje dowolny jeden znak oraz '%' - zastępuje dowolny
ciąg znaków. Przykład:
SELECT * FROM klient WHERE imię LIKE 'Ja%';
Operator BETWEEN .. AND … - poznamy go poprzez przykład użycia:
SELECT * FROM klient where id_klienta BETWEEN 3 AND 7;
Operator IN() pozwala wybrać elementy z listy do porównania wartości:
SELECT * FROM klient WERE id IN(3,5,9);
SELECT * FROM klient WERE imie IN('Jan','Janina');
Operator IS pozwal na sprawdzenie, czy dana wartość jest NULL lub nie jest:
12
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
SELECT * FROM wypozyczenie WHERE data_zwrotu IS NULL;
SELECT * FROM wypozyczenie WHERE data_zwrotu IS NOT NULL;
Operatory i klauzulę WHERE można stosować w instrukcjach SELECT, UPDATE lub DELETE do
wybierania zakresu rekordów na których dokonywane będą przewidziane operacje. Dzięki
operatorom AND i OR można budować bardzo wyszukane warunki.
Kopie zapasowe i odzyskiwanie danych
W PostgreSQL możliwe jest wykonanie kopii zapasowej bazy danych. Można tego dokonać przy
pomocy polecenia systemowego pg_dump nazwabazy . W wyniku działania tego polecenia na
ekranie terminala pojawi się kod SQL , który pozwoli na ponowne założenie bazy danych.
Przykład:
Opuść bazę danych (\q)
pg_dump lab2_login
Teraz przekierujmy wynik działania polecenia do pliku:
pg_dump lab2_login > lab2_login_dump.sql
możesz teraz podejrzeć zawartość tego pliku np. przy pomocy edytora mcedit:
mcedit lab2_login_dump.sql
W tym miejscu połącz się za swoją bazą ponownie i poćwicz usuwanie danych.
Spróbuj skasować płyty, gatunki i wypożyczenia – zgodnie ze wskazówkami prowadzącego.
Teraz możliwe będzie odtworzenie tej bazy danych przy pomocy polecenia psql:
Usuńmy bazę danych: dropdb lab2_login
stwórzmy ją na nowo (będzie pusta) : createdb lab2_login
sprawdźmy, że jest pusta: psql lab2_login
\d
No relations found
\i lab2_login_dump.sql
\d
SELECT * FROM klient;
Widać, że nasza baza odzyskała postać i dane z pliku.
13
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
Zapytania złożone i widoki.
Przypomnijmy sobie zapytania złożone z wielu tabel, które przerabialiśmy podczas ostatnich zajęć.
Utrwalmy te zapytania w formie widoków.
SELECT k.imie, k.nazwisko, p.tytul,w.data_wypozyczenia,
w.data_zwrotu
FROM
klient k, wypozyczenie w, plyta p
WHERE
k.id_klienta = w.kto_wypozyczyl AND p.numer =
w.co_wypozyczyl;
SELECT
k.imie,
k.nazwisko,
p.tytul,w.data_wypozyczenia,
w.data_zwrotu
FROM klient k LEFT JOIN wypozyczenie w ON k.id_klienta =
w.kto_wypozyczyl LEFT JOIN plyta p ON p.numer = w.co_wypozyczyl;
oraz
SELECT
k.imie,
k.nazwisko,
p.tytul,w.data_wypozyczenia,
w.data_zwrotu
FROM
klient
k
JOIN
wypozyczenie
w
ON
k.id_klienta
=
w.kto_wypozyczyl RIGHT JOIN plyta p ON p.numer = w.co_wypozyczyl;
Ale struktura naszej Bazy danych jest dalece bardziej rozbudowana niż – spróbujmy zastem
wyświetlić zdecydowanie więcej danych. Zanim jednak to uczynimy dodajmy kila rekordów do
tablicy jest pracownikiem.
Pracownicy w naszej wypożyczalni to Jan Kowalski – przysługuje mu rabat 50 % i Adam Brzeski – z
rabatem 40 %. Zatem dodajmy odpowiednie wpisy do tabeli jest_pracownikiem:
INSERT
INTO
jest_pracownikiem(rabat,id_klienta)
VALUES((SELECT
id_klienta
from
klient
where
imie='Jan'
AND
nazwisko
=
'Kowalski'),50);
Podobnie zrób dla pana Adama Brzeskiego – z rabatem 40%.
Teraz przepisz zapytanie
wynikową w postaci:
w
imię | nazwisko | tytuł
data_zwrotu | cena | rabat
taki
|
sposób,
gatunek
|
żeby
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
tabelę
data_wypozyczenia
Łatwo zauważyć, że w pojedynczym zapytaniu z
klauzuli WHERE jako warunku łączącego tabele.
14
pokazało
|
wykorzystaniem
W wyniku tak
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
postawionego zapytania otrzymamy jedynie wiersze dla wszystkich
wypożyczonych płyt które mają gatunek i są wypożyczone przez
klienta będącego pracownikiem:
SELECT k.imie, k.nazwisko, p.tytul, g.nazwa, w.data_wypozyczenia,
w.data_zwrotu , p.cena, j.rabat FROM klient k, plyta p, gatunek g,
wypozyczenie w, jest_pracownikiem j
WHERE
k.id_klienta
=
w.kto_wypozyczyl
and
p.numer
=
w.co_wypozyczyl and k.id_klienta = j.id_klienta and p.gatunek =
g.id_gatunku;
Przyjrzyjmy się instrukcji warunkowej po klauzuli where:
k.id_klienta = w.kto_wypozyczyl and (prawdziwe dla wszystkich wypożyczeń)
p.numer = w.co_wypozyczyl
and (prawdziwe dla wszystkich wypożyczeń)
k.id_klienta = j.id_klienta
and (prawdziwe tylko dla pracowników)
p.gatunek = g.id_gatunku;(prawdziwe tylko dla płyt z wypełnionym gatunkiem)
Widać zatem, że część zapytania z komentarzem na czerwono znacznie ograniczy ilość
wyświetlanych wyników. Musimy zatem skorzystać z innej postaci połączenia tabel – przy pomocy
JOIN.
Sprawdźmy zatem jak zadziała połączenie join dla tych 5 tabel:
SELECT k.imie, k.nazwisko, p.tytul, g.nazwa, w.data_wypozyczenia,
w.data_zwrotu , p.cena, j.rabat
FROM
jest_pracownikiem j JOIN klient k ON k.id_klienta = j.id_klienta
JOIN wypozyczenie w ON k.id_klienta = w.kto_wypozyczyl
JOIN plyta p ON p.numer = w.co_wypozyczyl
JOIN gatunek g ON p.gatunek = g.id_gatunku;
Jak to działa i jaka jest kolejność złączeń? Sprawdźmy to na następującym rysunku, gdzie
odpowiednio j oznacza tabelę jest_pracownikiem, k – tabelę klient, w – tabelę wypozyczeie, p –
tabelę plyta i g tabelę gatunek:
j
k
w
j
g
Kolejne owale oznaczają tutaj kolejność łączeń.
Jako pierwsze połączenie występuje tutaj połączenie klienta z jest_pracownikiem. Tabela
jest_pracownikiem występuje po lewej stronie związku, ale powinniśmy w wyniku zapytania
wyświetlić wszystkich klientów – nawet jeśli nie są pracownikami. Chronimy zatem prawą stronę
związku tabel klient i jest_pracownikiem. Sprawdźmy jak zadziała ta część zapytania:
15
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
SELECT k.imie, k.nazwisko, j.rabat from jest_pracownikiem j JOIN
klient k ON k.id_klienta = j.id_klienta;
SELECT k.imie, k.nazwisko, j.rabat from jest_pracownikiem j RIGHT
JOIN klient k ON k.id_klienta = j.id_klienta;
Następną w kolejności złączeń tabelą jest wypożyczenie – dołączmy
ją do poprzedniego zapytania:
SELECT
k.imie,
k.nazwisko,
j.rabat,
w.data_wypozyczenia,
w.data_zwrotu from jest_pracownikiem j RIGHT JOIN klient k ON
k.id_klienta
=
j.id_klienta
JOIN
wypozyczenie
w
ON
w.kto_wypozyczyl = k.id_klienta;
Łatwo zauważyć, że taki JOIN zepsuje wynik RIGHT JOIN'a z poprzedniego zapytania. Ponieważ to
co chcemy chronić jest po lewej stronie związku – musimy skorzystać z LEFT JOIN w kolejnym
złączeniu. Sprawdźmy to:
SELECT
k.imie,
k.nazwisko,
j.rabat,
w.data_wypozyczenia,
w.data_zwrotu from jest_pracownikiem j RIGHT JOIN klient k ON
k.id_klienta
=
j.id_klienta
LEFT
JOIN
wypozyczenie
w
ON
w.kto_wypozyczyl = k.id_klienta;
Podobnie dołączmy płytę i gatunek:
SELECT k.imie, k.nazwisko, p.tytul, g.nazwa, w.data_wypozyczenia,
w.data_zwrotu , p.cena, j.rabat
FROM
jest_pracownikiem j RIGHT JOIN klient k ON k.id_klienta =
j.id_klienta
LEFT JOIN wypozyczenie w ON k.id_klienta = w.kto_wypozyczyl
LEFT JOIN plyta p ON p.numer = w.co_wypozyczyl
LEFT JOIN gatunek g ON p.gatunek = g.id_gatunku;
Utrwalmy podobne do powyższego zapytanie w formie widoku:
CREATE VIEW raport1 AS SELECT k.imie || ' ' || k.nazwisko,
p.tytul, g.nazwa, w.data_wypozyczenia, w.data_zwrotu , p.cena,
j.rabat
FROM
jest_pracownikiem j RIGHT JOIN klient k ON k.id_klienta =
j.id_klienta
LEFT JOIN wypozyczenie w ON k.id_klienta = w.kto_wypozyczyl
LEFT JOIN plyta p ON p.numer = w.co_wypozyczyl
LEFT JOIN gatunek g ON p.gatunek = g.id_gatunku;
16
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
Użyliśmy tutaj operatora łączenia ciągów znaków ||. Pozwala to na połączenie np. imienia i
nazwiska klienta tak, aby znalazły się w jednej kolumnie. Dodatkowo wymuszamy zmianę nazwy
wyświetlanej kolumny dyrektywą AS.
Funkcje agregacji
W poprzednim ćwiczeniu pokazana została funkcja, dzięki której można dokonać połączenia ciągu
znaków. Istnieje szereg innych funkcji – min matematycznych. Sprawdźmy działanie niektórych z
nich:
SELECT
SELECT
SELECT
SELECT
2+2;
sin(1);
log(numer) FROM plyta;
sin(cena) FROM plyta;
Ale istnieją także inne funkcje:
SELECT
SELECT
SELECT
SELECT
SELECT
count(*) FROM gatunek;
count(imie) FROM klient;
max(id_klienta) FROM klient;
min(id_klienta) FROM klient;
avg(id_klienta) FROM klient;
Te funkcje w odróżnieniu od poprzednich zwracają pojedynczy wynik a operują na grupach krotek.
Funkcje takie noszą miano funkcji agregacji, gdyż dokonują analizy na grupie krotek. Gdy
wykonamy funkcję sin(id_klienta) to zwróci ona tyle wyników na ilu krotkach się ona wykonała,
natomiast funkcje takie jak max(), min(), avg(), variance(), stdev() czy count() zwrócą pojedynczy
wynik.
Z tymi funkcjami związana jest dodatkowa klauzula zapytania SELECT : GROUP BY.
GROUP BY powoduje przestawienie wyników w taki sposób, aby stanowiły one „przegrupowaną”
tabelę względem kryterium. Na tak przegrupowanej tabeli możliwe jest wykonywanie funkcji
agregacji i dalsza analiza wyników. Przykładowo – chcemy dokonać statystycznego zestawienia
imion występujących w tabeli klient:
SELECT imię, count(imie) FROM klient GROUP BY imię;
Z klauzulą GOUP BY związana jest klauzula HAVING, która działa tak samo jak WHERE dla
„normalnej” wersji SELECT:
SELECT imię, count(imie) FROM klient GROUP BY imię HAVING imię <
'J';
17
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski
Politechnika Gdańska, międzywydziałowy kierunek „INŻYNIERIA BIOMEDYCZNA”
W ramach laboratorium pokazane zostały metody manipulowania danymi, operatory, zapytania
złożone, funkcje agregacji, klauzula GROUP BY oraz możliwość utrwalania zapytań w formie
widoków. Na następnych zajęciach wprowadzone zostaną szerzej funkcje i pokazane metody
dalszej analizy danych oraz transakcje.
18
BAZY DANYCH, laboratorium nr 2 , A. Bujnowski

Podobne dokumenty