Skapa exempeldatabasen Koden i detta dokument är avsedd att exekveras i SQL Editor i MySQL Workbench. Skapa databasen För att kunna använda svenska alfabetet för lagring av data deklareras teckenensuppsättningen som utf8_swedish_ci. För namn på variabler etc används engelska och vid behov swengelska. CREATE DATABASE work_schedule DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci Skapa tabellerna ER-diagrammet ser ut så här i Workbench Data Modeling-fönstret: STAFF: Anställda personer. JOBS: Uppdrag/jobb som ska utföras. TIMEUNITS: Tidsperioder med start- och sluttid (för närvarande är varje period 30 minuter lång). STAFF_PERIODS: En anställds arbetstider lagras som rader. Raden kopplas till en rad i STAFF och en i TIMEUNITS. Dubbletter förhindras genom att båda främmande nycklarna ingår i primärnyckeln. Alltså omöjligt att en personal blir dubbelbokad. Någon koppling behöver inte göras till JOBS pga delaktigheten i relationen är frivillig. Så här långt kommer då STAFF_PERIODS att för varje anställd innehålla en rad för varje tidsperiod som denne ska arbeta. När en anställd sedan tilldelas ett jobb, kopplas en rad i STAFF_PERIODS till den aktuella raden i JOBS för varje tidsperiod som denne ska arbeta med detta jobb. Det är omöjligt att koppla den anställde till mer än ett jobb för en tidsperiod. PROBLEM: Pga att tu_end för en tidsperiod är tu_begin för nästa period finns redundans. Vilka föroch nackdelar finner med detta jämfört med den redundansfria lösningen med enbart tu_begin?
Tabellen staff. En liten, enkel tabell som bara innehåller ett anställningsnummer och namn för fyra anställda. USE work_schedule; CREATE TABLE staff ( staff_id smallint(5) unsigned NOT NULL, staff_name varchar(45) COLLATE utf8_swedish_ci NOT NULL, PRIMARY KEY (staff_id) INSERT INTO staff VALUES (38,'Freya Vigdisdotter'), (123,'Anders Olsson'),(211,'Pernilla Berg'),(5345,'Nenad Vidivić'); Tabellen jobs CREATE TABLE jobs ( job_id int(10) unsigned NOT NULL AUTO_INCREMENT, job_descr varchar(300) COLLATE utf8_swedish_ci NOT NULL, PRIMARY KEY (job_id) Lagra några jobb som ska göras: INSERT INTO jobs VALUES (1,'Något att göra'), (2,'Mer att göra'),(3,'mycket att göra'),(4,'litet att göra'); Tabellen timeunits Tu_start: Starttiden för en period. Tu_slut: Sluttiden för en period, vilket med några få undantag är samma tid som startiden för nästa period. USE work_schedule; CREATE TABLE timeunits ( tu_id int NOT NULL AUTO_INCREMENT, tu_begin datetime NOT NULL, tu_end datetime NOT NULL, PRIMARY KEY (tu_id) Denna tabell ska innehålla samtliga perioder på vilka personalen kan schemaläggas. I exemplet nöjer vi oss med fyra dagar från klockan 8:00 till 17:00 varje dag i perioder om 30 minuter.
Ett skript som gör detta: USE work_schedule; /* Vid behov: För att tömma tabellen. Räknaren kan ej nollställas /* utan kommer att fortsätta från den senast använda numret. */ DELETE FROM timeunits WHERE tu_id >= 0; /* Loop måste i denna typ av skript ligga inne i en procedur. drop procedure if exists proc_name; //Ta bort om redan finns /* Ändra temporärt avgränsaren så att den vanliga semikolon kan */ /* användas inne i proceduren och $$ används för att ange var */ /* proceduren slutar. */ DELIMITER $$ CREATE PROCEDURE proc_name() BEGIN SET @days = 0; /* Antalet dagar från ett startdatum */ SET @interval = 30; /* Periodernas längd i minuter */ SET @date = '2012-03-08 08:00:00'; /* Startdatumet */ /* Tre varv blir tre dagar */ WHILE @days <= 2 DO SET @scheduledate = DATE_ADD(@date,INTERVAL @days day); SET @period = 0; /* Perioderna på dagen endast 3 stycken för att få överskådliga data */ WHILE @period < 3 DO /* Lagra som en rad i tabellen */ INSERT timeunits(tu_begin,tu_end) VALUES(DATE_ADD(@scheduledate, INTERVAL @period * @interval minute), DATE_ADD(@scheduledate, INTERVAL (@period + 1) * @interval minute) ); SET @period = @period + 1; /* Nästa period */ END WHILE; SET @days= @days + 1; /* Nästa dag */ END WHILE; END$$ DELIMITER ; /* Återställ avgränsaren */ /* Exekvera proceduren */ CALL proc_name; SELECT * FROM timeunits; /* Visa tabellens innehåll */ drop procedure if exists proc_name; //Ta bort proceduren Innehållet i time_units: tu_id tu_begin tu_end 1 2012-03-08 08:00:00 2012-03-08 08:30:00 2 2012-03-08 08:30:00 2012-03-08 09:00:00 3 2012-03-08 09:00:00 2012-03-08 09:30:00 4 2012-03-09 08:00:00 2012-03-09 08:30:00 5 2012-03-09 08:30:00 2012-03-09 09:00:00 6 2012-03-09 09:00:00 2012-03-09 09:30:00 7 2012-03-10 08:00:00 2012-03-10 08:30:00 8 2012-03-10 08:30:00 2012-03-10 09:00:00 9 2012-03-10 09:00:00 2012-03-10 09:30:00
Tabellen staff_periods. Denna tabell innehåller de perioder som respektive anställd ska arbeta. Var och en av dessa perioder för en anställd kan senare kopplas till ett av jobben i tabellen jobs. CREATE TABLE staff_periods ( staff_id smallint(5) unsigned NOT NULL, tu_id int(11) NOT NULL, job_id int(11) unsigned DEFAULT NULL, PRIMARY KEY (staff_id,tu_id), KEY fk1 (staff_id), KEY fk2 (tu_id), KEY fk3 (job_id), CONSTRAINT fk1 FOREIGN KEY (staff_id) REFERENCES staff (staff_id) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT fk2 FOREIGN KEY (tu_id) REFERENCES timeunits (tu_id) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT fk3 FOREIGN KEY (job_id) REFERENCES jobs (job_id) ON DELETE SET NULL ON UPDATE CASCADE Befolka tabellen med de perioder varje anställd ska arbeta. Freya Vidgisdotter (staff_id 38) ska arbeta alla perioderna 2012-03-08: INSERT staff_periods(staff_id, tu_id) SELECT "38", tu_id FROM timeunits WHERE tu_begin < "2012-03-09 00:00:00" Anders Olsson arbetar de två första perioderna perioderna varje dag (8:00 och 8:30): INSERT staff_periods(staff_id, tu_id) SELECT "123", tu_id FROM timeunits WHERE time(tu_begin) <= "08:30:00" Pernilla Berg ska arbeta alla perioderna den 9 mars och den första perioden (08:00) övriga dagar: INSERT staff_periods(staff_id, tu_id) SELECT "211", tu_id FROM timeunits WHERE date(tu_begin) = "2012-03-09" OR (date(tu_begin) <> "2012-03-09" AND time(tu_begin) = "08:00:00") Nenad Vividić har inte fått något arbetsschema.
Innehållet i staff_periods: SELECT * FROM staff_periods staff_id tu_id job_id 38 1 NULL 38 2 NULL 38 3 NULL 123 1 NULL 123 2 NULL 123 4 NULL 123 5 NULL 123 7 NULL 123 8 NULL 211 1 NULL 211 4 NULL 211 5 NULL 211 6 NULL 211 7 NULL Med perioderna i klartext: SELECT staff_id, tu_begin, tu_end FROM staff_periods s, timeunits t ORDER BY staff_id, tu_begin staff_id tu_begin tu_end job_id 38 2012-03-08 08:00:00 2012-03-08 08:30:00 NULL 38 2012-03-08 08:30:00 2012-03-08 09:00:00 NULL 38 2012-03-08 09:00:00 2012-03-08 09:30:00 NULL 123 2012-03-08 08:00:00 2012-03-08 08:30:00 NULL 123 2012-03-08 08:30:00 2012-03-08 09:00:00 NULL 123 2012-03-09 08:00:00 2012-03-09 08:30:00 NULL 123 2012-03-09 08:30:00 2012-03-09 09:00:00 NULL 123 2012-03-10 08:00:00 2012-03-10 08:30:00 NULL 123 2012-03-10 08:30:00 2012-03-10 09:00:00 NULL 211 2012-03-08 08:00:00 2012-03-08 08:30:00 NULL 211 2012-03-09 08:00:00 2012-03-09 08:30:00 NULL 211 2012-03-09 08:30:00 2012-03-09 09:00:00 NULL 211 2012-03-09 09:00:00 2012-03-09 09:30:00 NULL 211 2012-03-10 08:00:00 2012-03-10 08:30:00 NULL
Tilldela personalen jobb för de schemalagda perioderna. Freya Vidgisdotter (staff_id 38) ska arbeta med jobb 4 alla sina perioder: UPDATE staff_periods SET job_id = 4 WHERE staff_id = 38 Anders Olsson arbetar med jobb 4 den andra perioden (8:30) alla sina dagar : UPDATE staff_periods s, timeunits t SET s.job_id = 4 AND staff_id = 123 AND time(t.tu_begin) LIKE "08:30:00" Klockan 08:00 den 9 mars ska han arbete med jobb 2. UPDATE staff_periods s, timeunits t SET s.job_id = 2 AND staff_id = 123 AND t.tu_begin LIKE "2012-03-09 08:00:00" Pernilla Berg ska arbeta med jobb 1 alla perioderna den 9 mars: UPDATE staff_periods s, timeunits t SET s.job_id = 1 AND staff_id = 211 AND date(t.tu_begin) LIKE "2012-03-09" Innehållet i staff_periods: SELECT * FROM staff_periods s, timeunits t ORDER BY staff_id, tu_begin staff_id s.tu_id jobb_id t.tu_id t.tu_begin t.tu_end 38 1 4 1 2012-03-08 08:00:00 2012-03-08 08:30:00 38 2 4 2 2012-03-08 08:30:00 2012-03-08 09:00:00 38 3 4 3 2012-03-08 09:00:00 2012-03-08 09:30:00 123 1 1 2012-03-08 08:00:00 2012-03-08 08:30:00 123 2 4 2 2012-03-08 08:30:00 2012-03-08 09:00:00 123 4 2 4 2012-03-09 08:00:00 2012-03-09 08:30:00 123 5 4 5 2012-03-09 08:30:00 2012-03-09 09:00:00 123 7 7 2012-03-10 08:00:00 2012-03-10 08:30:00 123 8 4 8 2012-03-10 08:30:00 2012-03-10 09:00:00 211 1 1 2012-03-08 08:00:00 2012-03-08 08:30:00 211 4 1 4 2012-03-09 08:00:00 2012-03-09 08:30:00 211 5 1 5 2012-03-09 08:30:00 2012-03-09 09:00:00 211 6 1 6 2012-03-09 09:00:00 2012-03-09 09:30:00 211 7 7 2012-03-10 08:00:00 2012-03-10 08:30:00
Säkerhetskopia av tabellen staff_periods. Tabellen staff_periods uppdateras med värden på jobb_id, som knyter varje anställds arbetsperioder till ett jobb i tabellen jobs. För att inte förlora dessa mödosamt inlagda data görs en kopia av tabellen med tillhörande innehåll. En ny tabell för att lagra dessa data: create table staff_periods_orig ( staff_id smallint(5) unsigned NOT NULL, tu_id int(11) NOT NULL, job_id int(11) unsigned DEFAULT NULL Ingen nyckel eller främmande nyckel behövs, eftersom det bara är en kopia. Kopiera data från driftsversionen av tabellen till kopian: INSERT INTO staff_periods_orig SELECT * FROM staff_periods; När data i driftstabellen ska återställas efter våra experiment, är det bara till att tömma staff_periods och sedan kopiera in data från staff_periods_orig. En STORED PROCEDURE skapas för detta ändamål i mysql Workbench. I Object Broweser högerklickar du på Routines of väljer Create Routine. -- -------------------------------------------------------------------------------- -- Routine DDL -- Note: comments before and after the routine body will not be stored by the server -- -------------------------------------------------------------------------------- DELIMITER $$ CREATE PROCEDURE work_schedule.sp_restorestaffperiods () BEGIN DELETE FROM staff_periods; DELETE FROM staff; INSERT INTO staff VALUES (38,'Freya Vigdisdotter'), (123,'Anders Olsson'),(211,'Pernilla Berg'),(5345,'Nenad Vidivić'); INSERT INTO staff_periods SELECT * FROM staff_periods_orig; END Denna procedur kan sedan anropas från Java. Den tömmer tabellerna staff och staff_periods och lägger sedan in de urspungliga värdena. Demonstrationskoden kommer senare även att ändra i staff, och därför återskapar proceduren även de ursprungliga data i denna tabell. (Det går också att skapa den i samma fönster där man skriver vanlig SQL-kod.)
Säkerhetskopia av databasens struktur och innehåll. En god idé är att ha en säkerhetskopia av databasen så att den kan återskapas vid behov. Vid utvecklingsarbete händer det lätt att data blir tillrörda. Detta görs med administrationsdelen av Workbench. Funktionen data Export and Restore: Kryssa i schemat (work_schedule) och markera det. Markera alla tabellerna. Kryssa i Dump Stored Routines (Procedures and Functions). Kryssa i Export to Self_Contained file. Välj mapp där filen ska sparas och ge filen ett namn (i detta fall blev det work_schedule_restore.sql). Klicka Start export. Filen kan importeras från administrationsdelen av Workbench, funktionen Data Export and Restore. Fliken Import from disk. Kryssa i Import from Self-Contained File och bläddra till filen. Klicka sedan Start import. Alla tabeller och procedurer i databasen tas bort. Sedan återskapas de och fylls med sina data. På detta vis kan man också snabbt installera databasen på en annan dator. Det går att redigera work_schedule_restore.sql, men gör det endast, om du vet vad du gör.