Databáze čajových sáčků Martina Málková Západočeská univerzita v Plzni Katedra informatiky a výpočetní techniky Databázové systémy 2 9. června 2007 krovacek@students.zcu.cz 1
1 Datová analýza V původním datovém modelu bylo provedeno několik změn - převážně šlo o přidání dalších sloupců do tabulek foto čajovníka, logo firmy atp.. Přibyla také jedna tabulka pro určování typů čajů. Výsledný datový model je zobrazen na následujícím obrázku. Caje Obrázek 1: ERA model V dalších kapitolách budou popsány jednotlivé tabulky. Hlavní tabulka databáze. Jednotlivé položky jsou následující: Obrázek čaje není ukládán jako Image, jak bylo plánováno v původním modelu, ale nakonec jsem se rozhodla pro výhodnější ukládání jako nvarchar100, a tak umožnila obrázky čajů jednoduše fyzicky oddělit od vlastní databáze. hodnoceni je určená pro budoucí možnost hodnocení čaje od čajovníků. Pro to ale bude muset být zavedena tabulka Hodnoceni, kde budou jednotlivá hodnocení uložena. Toto v rámci této semestrální práce nebylo zpracováno, položka hodnocení prozatím slouží pouze pro hodnocení administrátorem. pocet kusu určuje počet kusů čaje, který je implicitně 1. 2
datum vlozeni je typu DateTime a je do ní automaticky vkládáno datum při vložení nového čaje řádku do tabulky. datum vymeny je implicitně null, je nastavena triggerem, pokud se počet kusů čaje zvýší nad 1 a opět vynulována pokud se vrátí na 1. TypCaje, Staty Tabulky pouze se seznamem typů čaje a států pro lepší práci s typy. Cajovnici Druhá nejdůležitější tabulka v databázi. Reprezentuje jednotlivé čajovníky, kteří si mohou zamlouvat jednotlivé čaje. Následují popisy jednotlivých položek: bf adresa je rozdělena do položek ulice, cp, mesto, psc bf jmeno, prijmeni, www, email, fotourl jsou standartní položky typu nvarchar50. Foto čajovníka je řešeno stejně jako u tabulky Caje. user id je klíč do systémové tabulky s registrovanými uživateli, kde je uživatelské jméno a heslo. Používá se pouze při přihlášení, jinak se pracuje s položkou id cajovnika. admin je položka typu bit, která pouze určuje zda je uživatel admin. Tato položka je nastavena ručně na jednoho administrátora a není umožněna její programová změna možná pouze prozatím. Firmy, Obchody Přibližně stejné složení jako je u tabulky Cajovnici. Sehnane, Zamluvene Pomocné tabulky pro realizaci propojení typu M:N, neobsahují žádné informace navíc pouze dvojice klíčů Logy Tabulka pouze pro logování změn v ostatních tabulkách. Do ní zapisuje pouze trigger, není umožněno provádět jiné změny dat. Povinnými parametry při vkládání do tabulky je jmeno tabulky a typ zmeny určující jaká operace byla nad tabulkou provedena. id zaznamu určuje id změněného záznamu v tabulce, polozka reprezentuje název sloupce, který se změnil, a nove, stare novou a starou hodnotu položky. 3
2 Funkční analýza V této kapitole budou popsány jednotlivé procedury a triggery. Procedury pro vkládání, mazání, update Tyto procedury jsou všechny podobné, proto zde budou vybrány pouze ukázky kódu pro každý typ akce. Vkládání do tabulky Cajovnici CREATE PROCEDURE dbo.vlozcajovnika @user_id uniqueidentifier, @jmeno nvarchar50, @prijmeni nvarchar50 = NULL, @www nvarchar50 = NULL, @datum_narozeni datetime = NULL, @id_statu int = 0, @ulice nvarchar50 = NULL, @cp nvarchar50 = NULL, @mesto nvarchar50 = NULL, @psc nvarchar50 = NULL, @email nvarchar50 = NULL, @fotourl nvarchar100=null TRY INSERT INTO Cajovniciuser_id, jmeno, prijmeni, www, datum_narozeni, id_statu, ulice, cp, mesto, psc,email,fotourl VALUES @user_id, @jmeno, @prijmeni, @www, @datum_narozeni, @id_statu, @ulice, @cp, @mesto, @psc,@email,@fotourl END TRY CATCH -1 END CATCH @@IDENTITY Mazání z tabulky Caje Integrita dat při mazání je zajištěna ve všech tabulkách - při mazání uživatele se vymažou jeho zamluvené čaje, při mazání firmy jsou smazány její čaje, při mazání obchodu smazány položky z tabulky Sehnane. CREATE PROCEDURE dbo.smazcaj @id_caje int DELETE FROM Caje WHERE id_caje = @id_caje; 4
Update Firmy Všechny položky jsou povinne, protože update probíhá v klientovi pouze přepisováním načtených dat. Vždy tedy bude co ukládat i prázdná položka v případě smazání některého údaje. CREATE PROCEDURE dbo.updatefirmy @id_firmy integer, @jmeno nvarchar50, @www nvarchar50, @ulice nvarchar50, @cp nvarchar50, @mesto nvarchar20, @psc nvarchar50 UPDATE Firmy SET jmeno = @jmeno, www = @www, ulice = @ulice, cp = @cp, mesto = @mesto, psc = @psc WHERE id_firmy = @id_firmy; Jednoduché procedury typu SELECT V databázi je také řada jednoduchých procedur pro vracení jedné hodnoty - např. VratID- Cajovnika@user id, VratIDStatu@jmeno,...,VratJmenoStatu@id statu, JeSpravce@user id. Zajímavější je pouze procedura VratIDStatu, která je vytvořena tak, aby v případě neexistujícího jména státu stát tohoto jména vytvořila a vrátila jeho nové ID. CREATE PROCEDURE dbo.vratidstatu @stat varchar20 declare @id integer; set @id = -1; SELECT @id = id_statu FROM Staty WHERE jmeno = @stat IF@id = -1 INSERT INTO Staty [jmeno] VALUES @stat SET @id = SCOPE_IDENTITY; END SELECT @id [result]; 5
Další procedury PocetCaju Byla vytvořena pro realizaci agregovaného dotazu. Vrátí celkový počet čajů v databázi. CREATE PROCEDURE dbo.pocetcaju @id_firmy int = NULL SELECT COUNT* FROM Caje c WHERE @id_firmy is NULL or @id_firmy = c.id_firmy; ZrusZamluveni Zruší zamluvený čaj některého z čajovníků následně přičte počet kusů v tabulce čaje, přestože by toto šlo řešit také triggerem nad tabulkou Zamluvene. Je zde uvedena hlavně jako případ volání uložené procedury z jiné. CREATE PROCEDURE dbo.zruszamluveni @id_caje int, @id_cajovnika int DELETE FROM Zamluvene WHERE id_caje = @id_caje AND id_cajovnika = @id_cajovnika; EXECUTE PrictiCaj @id_caje; TopCaje Vypíše čaje s hodnocením vyšším nebo rovným než dané ohodnocení, implicitně jen čaje s nejvyšším ohodnocením. CREATE PROCEDURE [dbo].[topcaje] @do_urovne int = 5 /* implicitne 5 */ SELECT c.jmeno, f.jmeno as firma, c.typ, c.datum_vlozeni, c.hodnoceni, c.obrazek FROM Caje c, Firmy f WHERE c.id_firmy = f.id_firmy AND c.hodnoceni >= @do_urovne; 6
Triggery Změna položky Datum vymeny v tabulce Cajovnici Při updatu tabulky jsou nové hodnoty změněných položek uloženy v systémové tabulce INSERTED a staré hodnoty v tabulce DELETED. CREATE TRIGGER logy_caje_pocet ON dbo.caje FOR UPDATE declare @old_pocet INTEGER SELECT @old_pocet = pocet_kusu FROM deleted declare @new_pocet INTEGER SELECT @new_pocet = pocet_kusu FROM inserted declare @id INTEGER select @id = id_caje from inserted IF@old_pocet < 2 AND @new_pocet >= 2 DECLARE @datum DATETIME set @datum = SELECT GETDATE select @datum as [dnesni datum a cas] UPDATE Caje SET datum_vymeny = @datum WHERE id_caje = @id END ELSE IF @old_pocet >= 2 AND @new_pocet < 2 UPDATE Caje SET datum_vymeny = NULL WHERE id_caje = @id END Odečtení kusů čaje při zamluvení Toto je realizováno triggerem na insert v tabulce Zamluvene. Je volána procedura, která odečte jeden kus čaje daného id. ALTER TRIGGER Zamluveni ON dbo.zamluvene FOR INSERT declare @id_caje int select @id_caje = id_caje FROM Inserted; execute OdectiCaj @id_caje; 7
Logování Zde byla snaha o nepsání příliš kódu víckrát, proto vzniklo několik procedur. V každém triggeru vypadal kód podobně, proto zde budou uvedeny triggery pouze z tabulky Caje: CREATE TRIGGER logy_caje_del ON dbo.caje AFTER DELETE declare @id_zaznamu INT select @id_zaznamu = $identity FROM DELETED; EXECUTE Loguj Caje, D, @id_zaznamu END; CREATE TRIGGER [dbo].[logy_caje_ins] ON dbo.caje AFTER INSERT declare @id_zaznamu INT select @id_zaznamu = $identity FROM INSERTED; EXECUTE Loguj Caje, I, @id_zaznamu END; CREATE TRIGGER logy_caje_up ON dbo.caje AFTER UPDATE select * INTO ##Tmp_ins from INSERTED select * into ##Tmp_del from DELETED EXECUTE VytvorLog Caje DROP TABLE ##Tmp_ins DROP TABLE ##Tmp_del END; Při updatu bylo potřeba zjistit také změněný sloupec a jeho starou a novou hodnotu, což bylo dosaženo pomocí kurzorů. Trigger pro update volá tedy nejprve proceduru VytvorLog, která požadované hodnoty zjistí a pak až zavolá proceduru Loguj, která už pouze zapisuje do tabulky Logy. ALTER PROCEDURE dbo.vytvorlog @jmeno_tabulky NVARCHAR50 declare @id INTEGER declare @nazev_sloupce NVARCHAR255 declare @query NVARCHAR255 declare @nova_hodnota NVARCHAR100 declare @stara_hodnota NVARCHAR100 declare @new_id_zaznamu INTEGER select @id = object_id 8
from sys.all_objects where name = @jmeno_tabulky declare sloupce cursor for select [name] from sys.all_columns where object_id = @id select @new_id_zaznamu = $identity FROM ##Tmp_ins; create table #Tmp_var klic VARCHAR50, hodnota VARCHAR100 open sloupce fetch next from sloupce into @nazev_sloupce WHILE @@FETCH_STATUS = 0 SET @query = INSERT INTO #Tmp_varklic, hodnota SELECT 1, +@nazev_sloupce+ FROM ##Tmp_ins EXEC@query SET @query = INSERT INTO #Tmp_varklic, hodnota SELECT 2, +@nazev_sloupce+ FROM ##Tmp_del EXEC@query SELECT @stara_hodnota = hodnota FROM #Tmp_var WHERE klic = 1 SELECT @nova_hodnota = hodnota FROM #Tmp_var WHERE klic = 2 IF@stara_hodnota <> @nova_hodnota EXECUTE Loguj @jmeno_tabulky = Caje, @typ_zmeny = U, @id_zaznamu = @new_id_zaznamu, @polozka = @nazev_sloupce, @nove = @nova_hodnota, @stare = @stara_hodnota fetch next from sloupce into @nazev_sloupce END close sloupce deallocate sloupce CREATE PROCEDURE dbo.loguj @jmeno_tabulky NVARCHAR20, @typ_zmeny CHAR1, @id_zaznamu INTEGER, @polozka NVARCHAR20 = NULL, @nove NVARCHAR20 = NULL, @stare NVARCHAR20 = NULL INSERT INTO Logyjmeno_tabulky, typ_zmeny, uzivatel, id_zaznamu, polozka, nove, stare VALUES @jmeno_tabulky, @typ_zmeny, system_user, @id_zaznamu, @polozka, @nove, @stare; 9