create table Artysta ( id serial primary key, imie varchar(20) NOT NULL, nazwisko varchar(30) NOT NULL, rok_urodzenia integer NOT NULL, rok_smierci integer, unique(imie, nazwisko), --ograniczenie zeby nie dodac dwa razy tego samego artysty, zakladam ze jesli nazywaja sie tak samo to dodamy np drugie imie check (rok_smierci > rok_urodzenia) ); create table Eksponat ( id serial primary key, tytul varchar(40), typ varchar(20) NOT NULL, szerokosc integer NOT NULL, wysokosc integer NOT NULL, waga integer NOT NULL, artysta serial references Artysta, czy_cenny char(3) NOT NULL check (czy_cenny in ('tak', 'nie')), czy_wypozyczony char(3) NOT NULL check (czy_wypozyczony in ('tak', 'nie')), czy_wystawiony char(3) NOT NULL check (czy_wystawiony in ('tak', 'nie')), check (not (czy_cenny = 'tak' and czy_wypozyczony = 'tak')), -- Zabrania ustawienia obu wartości na 'tak', nie można wypozyczyc jeśli jest cenny check (not (czy_wystawiony = 'tak' and czy_wypozyczony = 'tak')), galeria varchar(40), sala integer, check (not (czy_wystawiony = 'tak' and (galeria is null or sala is null))), -- musi być informacja o galerii i sali jeśli jest wystawiony unique (tytul, artysta) -- ograniczenie zeby nie dodac dwa razy tego samego dziela ); create table Instytucja ( id serial primary key, nazwa varchar(40) NOT NULL, miasto varchar(40) NOT NULL, unique (nazwa, miasto) ); create table Historia_wypozyczen ( eksponat serial NOT NULL references Eksponat, instytucja serial NOT NULL references Instytucja, data_wypozyczenia date NOT NULL, data_zwrotu date NOT NULL check (data_zwrotu > data_wypozyczenia) -- zakładam ze nawet jeśli nie jest jeszcze zwrocony to trzeba podac oczekiwana date zwrotu ); CREATE OR REPLACE FUNCTION check_cenny_wypozyczony_trigger() RETURNS TRIGGER AS $$ BEGIN IF NEW.czy_cenny = 'tak' AND NEW.czy_wypozyczony = 'tak' THEN RAISE EXCEPTION 'Nie można wypożyczyć eksponatu, który jest cenny!'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER check_cenny_wypozyczony_trigger BEFORE INSERT OR UPDATE ON Eksponat FOR EACH ROW EXECUTE FUNCTION check_cenny_wypozyczony_trigger(); CREATE OR REPLACE FUNCTION check_insert_czy_wypozyczony() RETURNS TRIGGER AS $$ BEGIN IF NEW.czy_wypozyczony = 'tak' THEN RAISE EXCEPTION 'Nie można ustawić czy_wypozyczony = "tak" podczas dodawania eksponatu. Nie widnieje jego aktualne wypożyczenie w tabeli Historia_wypozyczen.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER check_czy_wypozyczony_trigger BEFORE INSERT ON Eksponat FOR EACH ROW EXECUTE FUNCTION check_insert_czy_wypozyczony(); -- Tu ustawiam automatyczny update wartości czy_wypozyczony i czy_wystawiony w tabeli Eksponat korzystając z dat w tabeli Historia_wypozyczen: CREATE OR REPLACE FUNCTION update_czy_wypozyczony() RETURNS TRIGGER AS $$ BEGIN -- Ustawienie 'czy_wypozyczony' na 'nie' dla eksponatów, które mają zakończone wypożyczenie UPDATE Eksponat SET czy_wypozyczony = 'nie' WHERE id IN ( SELECT eksponat FROM Historia_wypozyczen WHERE data_zwrotu < CURRENT_DATE OR data_wypozyczenia > CURRENT_DATE ); -- Ustawienie 'czy_wypozyczony' na 'tak' oraz czy_wystawiony na 'nie' dla eksponatów, które mają wypożyczenie aktywne dzisiaj UPDATE Eksponat SET czy_wystawiony = 'nie', czy_wypozyczony = 'tak' WHERE id IN ( SELECT eksponat FROM Historia_wypozyczen WHERE data_wypozyczenia <= CURRENT_DATE AND data_zwrotu >= CURRENT_DATE ); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_update_czy_wypozyczony AFTER INSERT OR UPDATE ON Historia_wypozyczen FOR EACH ROW EXECUTE FUNCTION update_czy_wypozyczony(); -- Tu ustawiam error, żeby nie można było wypozyczyc eksponatu w okresie w którym wypożyczone sa wszystkie pozostale dziela tego artysty: CREATE OR REPLACE FUNCTION check_count_function() RETURNS TRIGGER AS $$ DECLARE liczba_wypozyczen INTEGER; -- Liczba dzieł wypożyczonych w danym okresie liczba_dziel_artysty INTEGER; -- Całkowita liczba dzieł danego artysty nasz_artysta INTEGER; BEGIN -- Zadeklaruj naszego artystę SELECT artysta INTO nasz_artysta FROM Eksponat WHERE id = NEW.eksponat; -- Policz liczbę dzieł artysty SELECT COUNT(*) INTO liczba_dziel_artysty FROM Eksponat WHERE artysta = nasz_artysta; -- Policz liczbę dzieł wypożyczonych w danym okresie (z wyłączeniem aktualnego eksponatu) SELECT COUNT(DISTINCT e.id) INTO liczba_wypozyczen FROM Historia_wypozyczen hw JOIN Eksponat e ON hw.eksponat = e.id WHERE e.artysta = nasz_artysta AND hw.eksponat != NEW.eksponat -- Wyklucz bieżący eksponat AND hw.data_wypozyczenia <= NEW.data_zwrotu -- Okresy wypożyczeń nachodzą na nowy AND hw.data_zwrotu >= NEW.data_wypozyczenia; -- Jeśli liczba wypożyczeń pokrywających się z nowym okresem jest równa liczbie dzieł artysty, zgłoś wyjątek IF (nasz_artysta IS NOT NULL AND liczba_wypozyczen >= liczba_dziel_artysty - 1) THEN RAISE EXCEPTION 'Nie można wypożyczyć eksponatu, ponieważ jest to ostatni niewypożyczony eksponat tego artysty w tym okresie.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER check_count BEFORE INSERT OR UPDATE ON Historia_wypozyczen FOR EACH ROW EXECUTE FUNCTION check_count_function(); -- Tu ustawiam error, żeby nie można było wypozyczyc eksponatu jeśli liczba dni jego wypozyczenia przekracza 30: CREATE OR REPLACE FUNCTION sprawdz_limit_wypozyczen() RETURNS TRIGGER AS $$ DECLARE laczna_liczba_dni integer; BEGIN -- Obliczenie łącznej liczby dni wypożyczeń dla danego eksponatu w bieżącym roku SELECT COALESCE(SUM(data_zwrotu - data_wypozyczenia + 1), 0) INTO laczna_liczba_dni FROM Historia_wypozyczen WHERE eksponat = NEW.eksponat AND EXTRACT(YEAR FROM data_wypozyczenia) = EXTRACT(YEAR FROM NEW.data_wypozyczenia); -- Sprawdzenie, czy łączna liczba dni przekroczy 30 IF laczna_liczba_dni + (NEW.data_zwrotu - NEW.data_wypozyczenia + 1) > 30 THEN RAISE EXCEPTION 'Nie można wypożyczyć eksponatu. Limit 30 dni w roku został przekroczony.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER sprawdz_limit_wypozyczen_trigger BEFORE INSERT ON Historia_wypozyczen FOR EACH ROW EXECUTE FUNCTION sprawdz_limit_wypozyczen(); -- Tu ustawiam error, żeby nie można było wypozyczyc eksponatu jeśli w tym okresie jest on już wypożyczony: CREATE OR REPLACE FUNCTION sprawdz_czy_mozna() RETURNS TRIGGER AS $$ BEGIN IF EXISTS (SELECT 1 FROM Historia_wypozyczen WHERE (eksponat = NEW.eksponat AND data_wypozyczenia <= NEW.data_zwrotu AND data_zwrotu >= NEW.data_wypozyczenia)) THEN RAISE EXCEPTION 'W tym terminie eksponat jest już wypożyczony.'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER sprawdz_czy_mozna_trigger BEFORE INSERT ON Historia_wypozyczen FOR EACH ROW EXECUTE FUNCTION sprawdz_czy_mozna();