-- merge naredba 

-- 1. napisati sledece sql naredbe:

--    a) kreirati tabelu predmetStudent u kojoj cuvamo koliko j estudenata polozilo neki predmet
--      idPredmeta, brStudenata idPredmeta primarni i strani kljuc na tabelu predmet

CREATE TABLE da.predmetStudent(
	idPredmeta INTEGER NOT NULL PRIMARY KEY,
	brStudenata INTEGER,
	FOREIGN KEY fkps_predmet(idPredmeta) REFERENCES da.predmet
)@

--   b) popuniti tabelu predmetStudent svi obaveznim predmetima sa smera Informatika
--      na osnovnim akademskim studijama, brStudenata svima postaviti na 5

INSERT INTO da.predmetStudent(idPredmeta, brStudenata)
SELECT pp.idpredmeta, 5
FROM da.predmetprograma pp
WHERE pp.idprograma IN (SELECT id FROM da.studijskiprogram sp
						WHERE sp.naziv = 'Informatika' AND sp.idnivoa IN (SELECT id 
																		  FROM da.nivokvalifikacije
																		  WHERE naziv = 'Osnovne akademske studije'))@
																		  
-- c) azurirati informacije u tabeli predmetStudenti(dodati sve predmete i one koji
--   su vec u tabeli azurirati ispravnim informacijama)

MERGE INTO da.predmetStudent ps
USING (
	SELECT p.id, COUNT(i.indeks) brStudenata
	FROM da.predmet p LEFT JOIN da.ispit i
			ON i.idpredmeta = p.id
			AND ocena > 5 AND status = 'o'
	GROUP BY p.id
) as real_data																	  																	  
ON ps.idPredmeta = real_data.id
WHEN MATCHED THEN UPDATE SET ps.brStudenata = real_data.brStudenata
WHEN NOT MATCHED THEN INSERT VALUES (real_data.id, real_data.brStudenata)@
  
SELECT * FROM da.predmetStudent@

DROP TABLE da.predmetStudent@
---------------------------------------------------------------------

-- 2.
--- a) napraviti tabelu studentPodaci u kojo cuvamo sledec informacije:
--     indeks, brpolpred, prosek, datum upisa

CREATE TABLE studentPodaci(
	indeks INTEGER NOT NULL PRIMARY KEY,
	brPred SMALLINT,
	prosek FLOAT,
	datUpisa DATE,
	FOREIGN KEY fksp_dosije(indeks) REFERENCES dosije)@

-- b) popuniti tabelu sledecim informacijama:
--    studente sa prosecima preko 8 ubaciti indeks, brpred, prosek
--    studenti koji su diplomirali indeks, 40, 10

INSERT INTO studentPodaci(indeks, brPred, prosek)
WITH diplomirani AS (
	SELECT indeks
	FROM dosije
	WHERE idstatusa IN (SELECT id FROM studentskistatus
						WHERE naziv = 'Diplomirao')
)
SELECT i.indeks, COUNT(i.idpredmeta), AVG(i.ocena + 0.0)
FROM ispit i
WHERE i.ocena > 5 AND i.status = 'o'
	AND i.indeks NOT IN (SELECT indeks FROM diplomirani)
GROUP BY i.indeks
HAVING AVG(i.ocena + 0.0) > 8
UNION
SELECT indeks, 40, 10.0
FROM diplomirani@

SELECT * FROM studentPodaci@


-- c) azurirati informacije iz tabelee studentPodaci
--   svima koji su diplomirali da unesemo datumupisa
--   onima koji su u tabeli i na budzetu azurirati brpredmeta i prosek
--   onima koji su u tabeli a status im je ispisan - obrisati ih
--   onima koji nisu u tabeli i nisu ispisani uneti sve osim datuma upisa
--   sve ostalo ignorisati

MERGE INTO studentPodaci sp
USING (
	SELECT d.indeks, COUNT( CASE
								WHEN i.ocena > 5 AND status = 'o' THEN i.idpredmeta
								ELSE NULL
							END) brPredmeta,
					AVG(CASE
							WHEN ocena > 5 AND status = 'o' THEN ocena + 0.0
							ELSE NULL
						END) prosek, 
						ss.naziv,
						d.datupisa
	FROM dosije d LEFT JOIN ispit i	
			ON d.indeks = i.indeks
		LEFT JOIN studentskistatus ss
			ON d.idstatusa = ss.id
	GROUP BY d.indeks, ss.naziv, d.datupisa
) AS real_data
ON sp.indeks = real_data.indeks
WHEN MATCHED AND real_data.naziv = 'Diplomirao' THEN
	UPDATE SET sp.datUpisa = real_data.datupisa
WHEN MATCHED AND real_data.naziv = 'Budzet' THEN
	UPDATE SET (sp.brPred, sp.prosek) = (real_data.brPredmeta, real_data.prosek)
WHEN MATCHED AND real_data.naziv = 'Ispisan' THEN
	DELETE
WHEN NOT MATCHED AND real_data.naziv != 'Ispisan' THEN
	INSERT (indeks, brPred, prosek)
	VALUES (real_data.indeks, real_data.brPredmeta, real_data.prosek)
ELSE IGNORE@

-- d) obrisatu tabelu..

DROP TABLE studentPodaci@

------------------------------------------------------------------------

-- okidac koji zabranjuje brisanje studenata koji su diplomirali:
CREATE OR REPLACE TRIGGER dosijeBrisanjeDipl
	BEFORE DELETE ON dosije
	REFERENCING OLD AS staro
	FOR EACH ROW
	WHEN (staro.idstatusa IN (SELECT id 
							 FROM studentskistatus 
							 WHERE naziv = 'Diplomirao'))
    SIGNAL SQLSTATE '75000' ('Student ciji je status Diplomiran ne moze biti obrisan')@


INSERT INTO dosije
VALUES (11111111, 101, 'Test', 'Test', 'm', 'Beograd', -2, '2015-07-06', '2019-09-12')@

INSERT INTO dosije
VALUES (11111112, 101, 'Test', 'Test', 'm', 'Beograd', 1, '2015-07-06', '2019-09-12')@

SELECT * FROM dosije WHERE ime = 'Test'@

DELETE FROM dosije WHERE ime = 'Test'@ -- ova naredba ispaljuje gresku sa SQLSTATE 75000(koji smo naveli)

DROP TRIGGER dosijeBrisanjeDipl@

DELETE FROM dosije WHERE ime = 'Test'@ -- kako smo okidac obrisali ovo sada prolazi

---------------------------------------------------------------------------

-- primer pracenja aktivnosti na bazi

CREATE TABLE imena(
	ime VARCHAR(20) NOT NULL PRIMARY KEY
)@

-- u tabeli pamtimo ime korisnika, timestamp pristupa i tip menjanja podataka na bazi
CREATE TABLE log_imena(
	ime_korisnika VARCHAR(100) NOT NULL,
	vreme_pristupa TIMESTAMP  NOT NULL,
	tip_pristupa CHAR  NOT NULL
)@

CREATE OR REPLACE TRIGGER menjanje_imena
AFTER INSERT OR DELETE OR UPDATE OF ime ON imena
FOR EACH ROW
BEGIN
	IF INSERTING THEN INSERT INTO log_imena VALUES(user, current_timestamp, 'i');
  	ELSEIF DELETING THEN INSERT INTO log_imena VALUES(user, current_timestamp, 'd');
  	ELSEIF UPDATING THEN INSERT INTO log_imena VALUES(user, current_timestamp, 'u');

	END IF;
END@

INSERT INTO imena VALUES ('neko ime')@

UPDATE imena SET ime='neko ime2' WHERE ime = 'neko ime'@

DELETE FROM imena@

SELECT * FROM log_imena@ -- vidimo 3 pristupa bazi

INSERT INTO imena
SELECT DISTINCT ime FROM dosije@

SELECT * FROM log_imena@ -- vidimo 453 pristupa bazi (3starta + 450 nova za insert)
                         -- ukoliko okidac umesto sa FOR EACH ROW opcijom kreiramo sa
                         -- FOR EACH STATEMENT mozemo videti da ce nakon ovog reda biti
                         -- samo 4 unosa (ceo insert se racuna kao jedan pristup)

DROP TRIGGER menjanje_imena@
DROP TABLE log_imena@
DROP TABLE imena@

----------------------------------------------------------

-- okidac koji forsira da se espb menja za njavise 1 bod

CREATE TRIGGER promenaESPB
BEFORE UPDATE OF espb ON predmet
REFERENCING OLD AS staro NEW AS novo
FOR EACH ROW
SET novo.espb = CASE
					WHEN staro.espb < novo.espb THEN staro.espb + 1
					WHEN staro.espb < novo.espb THEN staro.espb - 1
					ELSE staro.espb
				END
@

INSERT INTO predmet VALUES(1601, 'test', 'test', 4)@

SELECT * FROM predmet WHERE naziv = 'test'@

UPDATE predmet SET espb = 40 WHERE naziv = 'test'@

DROP TRIGGER promenaESPB@

----------------------------------------------------------------------

-- primer azuriranja vise tabela kroz okidac

CREATE TABLE broj_predmeta(
	broj INTEGER NOT NULL PRIMARY KEY
)@
	
CREATE TABLE broj_po_espb(
	espb INTEGER NOT NULL PRIMARY KEY,
	broj INTEGER
)@

INSERT INTO broj_predmeta
SELECT COUNT(*) FROM predmet@

INSERT INTO broj_po_espb
SELECT espb, COUNT(*)
FROM predmet
GROUP BY espb@

-- bitno je da obe tabele azuriramo atomicno
-- za to koristimo ATOMIC blok

CREATE TRIGGER predmetDEL
AFTER DELETE ON predmet
REFERENCING OLD AS stari
FOR EACH ROW
BEGIN ATOMIC
	UPDATE broj_predmeta SET broj = broj - 1;
	IF 0 = (SELECT COUNT(*) FROM predmet WHERE espb = stari.espb)
			 THEN DELETE FROM broj_po_espb WHERE espb = stari.espb;
	ELSE UPDATE broj_po_espb SET broj = broj - 1 WHERE espb = stari.espb;
	END IF;
END
@


CREATE TRIGGER predmetINS
AFTER INSERT ON predmet
REFERENCING NEW AS novi
FOR EACH ROW
BEGIN ATOMIC
	UPDATE broj_predmeta SET broj = broj + 1;
	IF 1 = (SELECT COUNT(*) FROM predmet WHERE espb = novi.espb)
			 THEN INSERT INTO broj_po_espb VALUES(novi.espb, 1);
	ELSE UPDATE broj_po_espb SET broj = broj + 1 WHERE espb = novi.espb;
	END IF;
END
@

SELECT * FROM broj_predmeta@

SELECT * FROM broj_po_espb@
SELECT * FROM broj_predmeta@

INSERT INTO predmet VALUES(1601, 'test', 'test', 11)@

DELETE FROM predmet WHERE naziv = 'test'@

DROP TRIGGER predmetDEL@
DROP TRIGGER predmetINS@

