Tu będzie full strona
projekt z baz danych, ale trochę trzeba poczekać
projekt z baz danych, ale trochę trzeba poczekać
Voilà diagram relacji (lub
tutaj
na tzw dużym ekranie).
Skrypt muzeum.sql inicjalizujący bazę danych psql
dla słynnego muzeum. odpowiada stosunkowo ściśle
diagramowi relacji uprzednio utworzonemu, ale jest mniej abstrakcyjny. Aczkolwiek
zrobiwszy taki oto model logiczny człowiek dostrzega, że diagram wymaga erraty.
Prócz samej logiczności modelu logicznego mam tutaj szkicoimplementację dwu triggerów. Dla jasności: nie jest to ich wersja ostateczna.
Na razie zajmuje się jedynie utworzeniem tabel, na dane jeszcze przyjdzie czas, plik
sql
-owy pojawi się gdzieś tu również.
drop table if exists Instytucja cascade;
drop table if exists Eksponat cascade;
drop table if exists Wypozyczenie cascade;
drop table if exists Ekspozycja cascade;
drop table if exists Artysta cascade;
create table Instytucja (
id_instytucji numeric(8) primary key,
nazwa varchar(31) not null,
miasto varchar(31) not null
);
-- jedynie artyści z naszych zasobów
create table Artysta (
id_artysty numeric(8) primary key,
imie varchar(31) not null,
-- nullable nazwisko? istotnie
-- https://en.wikipedia.org/wiki/Mononymous_person
nazwisko varchar(31),
urodziny date not null,
smierciny date
);
-- możemy sobie wyobrazić sztukę konceptualną nieposiadającą tytułu ni wymiarów
create table Eksponat (
id_eksponatu numeric(8) primary key,
tytul varchar,
typ varchar not null,
wysokosc numeric(8),
szerokosc numeric(8),
waga numeric(8),
dostepny boolean not null,
id_artysty numeric(8) references Artysta
);
-- połączenie instytucji z eksponatem
create table Wypozyczenie (
id_eksponatu numeric(8) references Eksponat,
id_instytucji numeric(8) references Instytucja,
poczatek date not null,
-- wypożyczamy tylko znając datę końca wypożyczenia, dyrektor muzeum
-- jest nieufny (a poza tym ułatwia to triggerowanie limitu 30 dni)
koniec date not null,
constraint wypo_k unique (id_instytucji, id_eksponatu)
);
-- połączenie eksponatu z galerią
create table Ekspozycja (
id_galerii numeric(8) not null,
id_eksponatu numeric(8) references Eksponat,
nr_sali numeric(8) not null,
poczatek date not null,
koniec date,
constraint ekspo_k unique (id_galerii, id_eksponatu)
);
-- kto się kryje i kurzy
create table Magazynienie (
id_eksponatu numeric(8) references Eksponat primary key,
poczatek date not null,
koniec date
);
-- uwaga: trzy powyższe tabele odpowiadają również za historię danego eksponatu!
-- użytkownik zechce dokonać odpowiednich zapytań
-- TRIGGERY
-- część warunków wynika ze struktry tabel np wśród Eksponatów
-- można mieć jedynie tych autorów, których mamy w rejestrze. Ale jednocześnie
-- każdego autora musimy mieć jakiś eksponat (o tym poniżej), co powoduje problem
-- jajkokurzy. Na szczęście zamiast robić na to trigger możemy po prostu
-- w naszym interfejsie umożliwić jedynie dodawanie jednocześnie tych dwu rzeczy,
-- czy coś w tym stylu.
--
-- Triggery niech się ograniczą do tych ograniczeń wynikłych nie ze struktur
-- relacji, a z działania naszego muzuem.
-- musimy zapewnić następujące warunki:
-- 1. eksponat może być poza muzeum maksymalnie 30 dni rocznie
-- 2. każdego z naszych artystów musimy posiadać przynajmniej jeden eksponat!
-- we support our people
-- ten trigger odpowiada za punkt 1., będzie się uruchamiał przy próbie dodania
-- wszelakich wypożyczeń BEFORE
create or replace function limit_obczyzny () returns trigger as $$
declare
ile_dni_rok integer;
begin
-- wstępna wersja, gdzie "w tym roku" oznacza "z koncem w tym roku"
with dlugosci(id_eksponatu, ile) as (
select w.id_eksponatu, w.koniec - w.poczatek + 1
from Wypozyczenie w
where date_part('year', w.koniec) = date_part('year', NEW.koniec)
)
select sum(ile) into ile_dni_rok
from dlugosci d
where d.id_eksponatu = NEW.id_eksponatu
group by d.id_eksponatu;
if ile_dni_rok + NEW.koniec - NEW.poczatek + 1 > 30 then
raise exception 'Eksponat byłby wypożyczony na ponad 30 dni w roku!';
end if;
return NEW;
end;
$$ language plpgsql;
create trigger t_obczyzna
before update or insert on Wypozyczenie
for each row execute procedure limit_obczyzny();
-- ten trigger natomiast obsługuje punkt 2., tj. posiadanie na stanie naszych
-- artystów. Będzie się odpalał AFTER.
create or replace function artysta_na_stanie () returns trigger as $$
declare
najmniej integer;
begin
-- licze tym wielkim zapytaniem dla kazdego artysty ile jego eksponatow
-- jest na stanie. najpierw biorę eksponaty na stanie, a potem grupuje po
-- artystach
with recursive eksponaty_na_stanie(id_eksponatu, id_artysty) as (
select mgz.id_eksponatu, mgz_id_artysty
from Magazynienie mgz
where mgz.poczatek < current_date
and (mgz.koniec > current_date or mgz.koniec is null)
union all
select glr.id_eksponatu, glr.id_artysty
from Ekspozycja glr
where glr.poczatek < current_date
and (glr.koniec > current_date or glr.koniec is null)
),
ile_dziel(id_artysty, ile) as (
select id_artysty, count(id_eksponatu)
from eksponaty_na_stanie
group by id_artysty
)
select min(ile) into najmniej from ile_dziel;
if ile = 0 then
raise exception 'Wyzerowano pewnego artystę!';
end if;
return NEW;
end;
$$ language plpgsql;
create trigger t_art_wyp
after update or insert on Wypozyczenie
for each row execute procedure artysta_na_stanie();