Harjoitustyö CSE-A1200 Tietokannat Jasse Lahdenperä 345396 killedwhale@kapsi.fi Henri Nurmi 345545 henri.nurmi@kapsi.fi 1
Ensimmäisen vaiheen ratkaisu ER-Kaavio 2
Relaatiomalli: Loanable(Id, MaximumLoanTime) Writing(Id, Name, Producers, Description, Class) Loan(Id, LoanDate, DueDate, Returned) Reservation(Id, DueDate) Customer(SSN, Name, Address, PhoneNumber) Office(Name, Address) Payment(Id, Amount, Reason, DueDate, DateOfPayment) Transport(Date, fromoffice, tooffice) CustomerHasPayment(SSN, PaymentId) CustomerHasLoan(SSN, LoanId) CustomerHasReservation(SSN, reservationid) LoanIsTypeLoanable(LoanId, LoanableId) ReservationHasWriting(ReservationId, WritingId) ReservationHasOffice(ReservationId, OfficeName) OfficeHasManyLoanable(OfficeName, LoanableId) OfficeStartsFromTransport(OfficeName, Date) TransportEndsToOffice(OfficeName, Date) TransportHasLoanable(LoanableId, Date) WritingIsTypeLoanable(WritingId, LoanableId) Kysymyksiä ja vastauksia: Mitä funktionaalisia riippuvuuksia tietokannassa vallitsee? Kaikilla avainatribuuteilla on funktionaalinen riipuvuus muihin atribuutteihin. Onko suunnitellussa tietokannassa anomalioita? Ei, tieto ei toistu, joten päivitysanomalioilta vältytään Myöskään poistoanomalioita ei ole sillä minkään datan poisto ei aiheuta muun datan menetystä Tosin esim. asiakkaan poistaminen saa aikaan poistorekursion Onko tietokanta Boyce-Codd-normaalimuodossa? Kyllä on 3
Ratkaisujen perusteluita: Toimiston nimi oletetaan muuttumattomaksi Jokaiselle suhteelle oma relaatio, kuten luentokalvoissa käsketään Suurin osa suhteista olisi kyllä järkevämpi (ainakin tilankäytön ja selkeyden kannalta) hoitaa foreignkeyllä lukuunottamatta seuraavia TransportHasLoanable tarvii oman taulunsa, koska loanable ei välttämättä kuulu mihinkään kuljetukseen Tämä siksi, että esim. Payment tai Loan liitetään suoraan yhteen asiakkaaseen Tosin voisi joissain tapauksissa aiheuttaa hassuja ristiriippuvuuksia Kuljetukset ajoitetaan niin ettei kahta kuljetusta lähde tismalleen samaan aikaan, jolloin kuljetuksen ajankohtaa voidaan käyttää avaimena Lainan Returned arvo on tyypiltään DateTime, joka on NULL jos lainaa ei ole vielä palautettu Maksun DateOfPayment on myös DateTime toimii kuten edellämainittu DataTimejen käytöllä saadaan ylläpidettyä historiaa lainoista ja maksuista näppärästi Writing on yksittäinen teos, joka on lainattavissa. Sen class-attribuutti kertoo sen tyypistä, eli siitä onko kyseessä esim CD vaiko kirja. 4
Päivitetty ER-Kaavio Lisättiin Loanable - Reservation relaatio ja lisättiin Reservable atribuutti Loanable taululle. Loan olisi toteutettavissa myös heikoilla yksilöjoukoilla, mutta nykyratkaisun avulla pystymme säilyttämään lainaushistorian. 5
Tyypilliset haut: Kirjaston tietokannasta pääsääntöisesti asiakkaan näkökulmasta etsitään lainattavia teoksia tiettyjen kriteerien perusteella, joita ovat esimerkiksi teoksen nimi, tekijä tai toimipiste jossa teos sijaitsee. Tietokannasta tullaan myös hakemaan asiakkaiden tietoja, näiden maksuja, lainaushistoriaa ja teosten kuljetuksia. Hakemistot: Avainten lisäksi hakemistot on päätetty luoda seuraaviin tauluihin: writing Indeksoidaan name ja producers. Koska näiden tietojen perusteella haetaan useimiten teoksia. loanable Indeksoidaan writing_id. Koska teoksen id:n peruustella haetaan toistuvasti lainattavia teoksia. reservation Indeksoidaan myös writing_id. Näkymät: Tietokantaan luotiin näkymät, jotka lajittelevat eri tyyppiset teokset omiin näkymiinsä atribuutin class perusteella. books dvds cds magazines Tyypilliset käyttötapaukset: Asiakas rekisteröityy kirjaston jäseneksi ja hänet tallennetaan kirjaston tietokantaan INSERT INTO customer (ssn, name, address, phone_number) VALUES ('123456-321D', 'Pekka Puupää', 'Otaniemi, 12345 Turku', '0700123123') ; Kirjasto perustaa uuden toimipisteen INSERT INTO office (name, address) VALUES ('Aalto-kirjasto', 'Otakaari 69, 00100 Espoo') ; 6
Kirjastoon tulee uusia teoksia ja lisätään näitä lainattaviksi eri toimipisteisiin INSERT INTO writing (name, producers, description, class) VALUES ('Gamasutra', 'Porno Tähti; Liekki Rakel', 'Book about positions', 'book'), ('Art of goatse', 'Tẑe Goa', 'Man sees best with open hole', 'book') ; INSERT INTO loanable(writing_id, office_name) VALUES (1, 'Aalto-kirjasto'), (1, 'Aalto-kirjasto'), (2, 'Aalto-kirjasto'), (3, 'TAIK-kirjasto'), (3, 'TAIK-kirjasto'), (3, 'TAIK-kirjasto') ; Asiakas lainaa teoksen toimipisteestä INSERT INTO loan(loanable_id, customer_ssn) VALUES (1, '110265-123M'), (2, '110265-123M') ; Kirjaston henkilökunta hakee palauttamattomat lainat, joiden palautuspäivämäärä on umpeutunut SELECT * FROM loan WHERE due_date < DATETIME('now') AND returned IS NULL; Tulos: 3 2014-04-01 13:37:00 2014-05-01 13:37:00 3 110265-123M Heti lainattavien teosten haku tekijän perusteella SELECT * FROM loanable LEFT JOIN writing ON writing.id == loanable.writing_id WHERE loanable.reservation_id IS NULL AND loanable.id NOT IN (SELECT loanable_id FROM loan WHERE returned IS NULL) AND writing.producers LIKE '%Jorma%' ; Tulos: 4 30 TRUE 3 TAIK-kirjasto 3 Suklaapuput Tillikka Jorma Kuuma elokuva suklaapupuista dvd 5 30 TRUE 3 TAIK-kirjasto 3 Suklaapuput Tillikka Jorma Kuuma elokuva suklaapupuista dvd 6 30 TRUE 3 TAIK-kirjasto 3 Suklaapuput Tillikka Jorma Kuuma elokuva suklaapupuista dvd 17 30 FALSE 3 Aalto-kirjasto 3 Suklaapuput Tillikka Jorma Kuuma elokuva suklaapupuista dvd 7
Lisätään lasku asiakkaalle myöhästyneestä palautuksesta INSERT INTO payment (amount, reason, due_date, customer_ssn) VALUES (5.20, "Muistutusmaksu", 1412553600, '110265-123M') ; Asiakas maksettua laskun, päivitetään lasku maksetuksi UPDATE payment SET date_of_payment = date('now') WHERE id = 2 ; Henkilökunta hakee maksamattomat laskut, joiden eräpäivä on mennyt umpeen SELECT * FROM payment, customer WHERE payment.customer_ssn = customer.ssn AND due_date < date('now') AND date_of_payment IS NULL ; Tulos: 1 5.2 Muistutusmaksu 1412553600 110265-123M 110265-123M Matti Haavikko Via Dolorosa 2 A, 00100 Espoo 401234567 Toimipisteen heti lainattavissa olevat teokset SELECT id FROM loanable WHERE office_name = 'Aalto-kirjasto' AND reservable='true' AND reservation_id IS NULL EXCEPT SELECT loanable.id FROM loan, loanable WHERE loan.loanable_id = loanable.id AND loanable.office_name = 'Aalto-kirjasto' AND returned IS NULL ; Tulos: 7 8 8
Alli hakee cd:tä nimeltä mesmerize ja toteaa että kyseistä teosta löytyy vai TAIKkirjastosta (writing_id = 7) SELECT loanable.writing_id AS writing_id, writing.name AS name, writing.description AS description, writing.class AS class, loanable.maximum_loan_time AS maximum_loan_time, loanable.reservable AS reservable, loanable.office_name AS office_name, COUNT(*) AS count, loanable.id IN (SELECT loanable_id FROM loan WHERE returned IS NULL) AS is_loaned, loanable.reservation_id IS NOT NULL AS is_reserved FROM loanable LEFT JOIN writing ON writing.id == writing_id WHERE class IS 'cd' AND name LIKE 'hypnotize' GROUP BY maximum_loan_time, reservable, writing_id, office_name, is_loaned ; Tulos: 7 Hypnotize cd - good music cd 30 TRUE TAIK-kirjasto 2 0 0 Alli tekee cd:lle varauksen ja haluaa sen kuljetettavan Aalto-kirjastoon INSERT into RESERVATION (customer_ssn, writing_id, office_name) VALUES ('715517-LUL3', 7, 'Aalto-kirjasto') ; INSERT INTO transport(date, start_office_name, end_office_name) VALUES (DATETIME('2014-05-22'), 'TAIK-kirjasto', 'Aalto-kirjasto') ; Lainattava täytyy myös merkitä kuljetukseen UPDATE loanable SET reservation_id = 1, transport_date = DATETIME('2014-05-22 00:00:00') WHERE id IN (SELECT id FROM loanable WHERE writing_id == 7 AND office_name == 'TAIK-kirjasto' AND id NOT IN (SELECT loanable_id FROM loan WHERE returned IS NULL) LIMIT 1) ; Muodostetaan asiakkaan lainaushistoria SELECT * FROM loan WHERE customer_ssn = 110265-123M ; Tulos: 1 2014-05-11 20:28:28 2014-06-10 20:28:28 1 110265-123M 2 2014-05-11 20:28:28 2014-06-10 20:28:28 2 110265-123M 3 2014-04-01 13:37:00 2014-05-01 13:37:00 3 110265-123M 9
SELECT name, address FROM office; Tulos: Aalto-kirjasto Otakaari 69, 00100 Espoo TAIK-kirjasto Arabianranta 12, 715517 Helsinki T-Talon kirjasto T-Talo Haetaan kaikkien toimipisteiden yhteistiedot 10