Databases I SQL Martin Caminada / Wiebren de Jonge Vrije Universiteit, Amsterdam definitieve versie 2002
Te behandelen querytalen relationele algebra domeincalculus tupelcalculus SQL
SQL meest gangbare querytaal relationele DBMSen aanvankelijk ontwikkeld vanuit IBM daarna: –1986: SQL1 (ANSI / ISO) –1992: SQL2 –inmiddels: SQL3 DDL + DML + VDL (in SQL1 ook enigszins SDL) DML gebaseerd op tupelcalculus en relationele algebra in dit college: DDL + DML + VDL van SQL2
Voorbeeld Database DEPARTMENT DNRNAMEBUDGET D1engineering500,000 D2sales200,000 DEPENDENT EMPLOYEEENRNAME REL ENRNAME BDATE DNR E3Mary daughter E1John D1 E3Sue wife E2Joe D1 E4Suzie daughter E3Jack D1 E4Tom son E4Will D2 E4Mary wife E5Bridget D2
create schema(DDL) CREATE SCHEMA COMPANY AUTHORIZATION MARTINC SQL schema bevat dingen zoals tables, constraints, views en domains idee: gescheiden databases op dezelfde DBMS mogelijk (security, naming)
create table (1/3)(DDL) CREATE TABLE DEPARTMENT (DNRCHAR(2)NOT NULL, NAMEVARCHAR(15)NOT NULL, BUDGET INT, PRIMARY KEY (DNR), UNIQUE (NAME));
create table (2/3)(DDL) CREATE TABLE EMPLOYEE (ENRCHAR(2) NOT NULL, NAMEVARCHAR(15)NOT NULL, BDATEDATE, DNR CHAR(2)DEFAULT “D1”, PRIMARY KEY (ENR), FOREIGN KEY (DNR) REFERENCES DEPARTMENT(DNR) ON DELETE SET NULL ON UPDATE CASCADE);
create table (3/3)(DDL) CREATE TABLE DEPENDENT (ENRCHAR(2)NOT NULL, NAMEVARCHAR(15)NOT NULL, RELVARCHAR(15), PRIMARY KEY (ENR, NAME), FOREIGN KEY (ENR) REFERENCES EMPLOYEE(ENR) ON DELETE CASCADE ON UPDATE CASCADE);
data types enkele SQL data types: –INT, SMALLINT –FLOAT –DECIMAL(i, j) (met i significante cijfers waarvan j achter de komma) –CHAR(n) –VARCHAR(n) –DATE (formaat: ‘YYYY-MM-DD’) –TIME (formaat: ‘HH:MM:SS’) –TIMESTAMP (bevat datum, tijd en fracties van seconde) –INTERVAL
create domain(DDL) CREATE DOMAIN NAME_DOMAIN AS VARCHAR(15); CREATE DOMAIN ENR_DOMAIN AS CHAR(2); CREATE DOMAIN DNR_DOMAIN AS CHAR(2); CREATE TABLE EMPLOYEE (ENRENR_DOMAIN NOT NULL, NAMENAME_DOMAIN NOT NULL, BDATEDATE, DNR DNR_DOMAIN, PRIMARY KEY (ENR), FOREIGN KEY (DNR) REFERENCES DEPARTMENT(DNR) ON DELETE SET NULL ON UPDATE CASCADE);
alter table(DDL) ALTER TABLE DEPENDENT ADD BDATE DATE; ALTER TABLE DEPARTMENT DROP BUDGET;
drop table(DDL) DROP TABLE DEPENDENT; DROP TABLE DEPARTMENT RESTRICT; DROP TABLE DEPARTMENT CASCADE; DROP SCHEMA COMPANY CASCADE;
insert (DML) INSERT INTO EMPLOYEE VALUES ("E1", "John", ' ', "D1"); INSERT INTO EMPLOYEE(ENR, NAME, BDATE, DNR) VALUES ("E1", "John", ' ', "D1"); INSERT INTO EMPLOYEE(ENR, NAME) VALUES ("E1", "John"); (DNR wordt default “D1”, BDATE wordt NULL) INSERT INTO EMPLOYEE(NAME, BDATE, DNR) VALUES ("John", ' ', "D1"); (mag niet want ENR mag geen NULL zijn)
update(DML) UPDATE DEPARTMENT SET BUDGET = WHERE NAME = “engineering”; UPDATE DEPARTMENT SET DNR = “D3” WHERE DNR = “D1”;
delete(DML) DELETE FROM DEPENDENT WHERE ENR = “E3” AND REL = “wife”; DELETE FROM EMPLOYEE WHERE NAME = “Will”; DELETE FROM EMPLOYEE;
voorbeeld query(DML) “Geef de naam en geboortedatum van de employees die in D2 werken” SELECTE.NAME, E.BDATE FROMEMPLOYEE AS E WHERE E.DNR = “D2”; alternatief: SELECTNAME, BDATE FROMEMPLOYEE WHERE DNR = “D2”; advies: gebruik altijd expliciete tupelvariabelen
algemene vorm queries(DML) Algemene vorm SQL query: SELECT FROM [WHERE ] [GROUP BY ] [HAVING ] [ORDER BY ];
voorbeeld query(DML) “Geef alle informatie uit de EMPLOYEE-tabel van de employees die in D2 werken” SELECT FROMEMPLOYEE AS E WHERE E.DNR = “D2”; “Geef de naam en geboortedatum van alle employees” SELECTE.NAME, E.BDATE FROMEMPLOYEE AS E;
voorbeeld query(DML) “Geef van elk department het DNR en het budget in guldens (er van uitgaande dat de budgetten in DEPARTMENT in euro’s zijn)” SELECTD.BUDGET FROMDEPARTMENT AS D; “Geef de naam en geboortedatum van de employees die in september geboren zijn” SELECTE.NAME, E.BDATE FROMEMPLOYEE AS E WHEREE.BDATE LIKE ‘____-09-__’;
voorbeeld query(DML) “Geef alle namen van dependents” SELECTD.NAME FROMDEPENDENT AS D; NAME Mary Sue Suzie Tom Mary Dubbele tupels worden in SQL niet verwijderd (behalve bij UNION / INTERSECT / EXCEPT)
voorbeeld query(DML) “Geef alle verschillende namen van dependents” SELECTDISTINCT D.NAME FROMDEPENDENT AS D; NAME Sue Suzie Tom Mary
voorbeeld query(DML) “Geef alle verschillende namen van dependents, in alfabetische volgorde” SELECTDISTINCT D.NAME FROMDEPENDENT AS D ORDER BYD.NAME; NAME Mary Sue Suzie Tom
voorbeeld query(DML) “Geef het gemiddelde department-budget” SELECTAVG(D.BUDGET) FROMDEPARTMENT AS D “Geef voor ieder department het DNR en het aantal emloyees” SELECTE.DNR, COUNT(E.ENR) FROMEMPLOYEE AS E GROUP BYE.DNR
voorbeeld query(DML) “Geef voor ieder department met meer dan 2 employees het DNR en het aantal employees” SELECTE.DNR, COUNT(E.ENR) FROMEMPLOYEE AS E GROUP BYE.DNR HAVINGCOUNT(E.ENR) > 2;
Voorbeeld Database EMPLOYEE ENRNAME BDATE DNR E1John D1 DNR=“D1” E2Joe D1 COUNT(ENR)=3 E3Jack D1 E4Will D2 DNR=“D2” E5Bridget D2 COUNT(ENR)=2
voorbeeld query(DML) “Geef voor ieder department met minstens één employee geboren voor 1970 het DNR en het aantal emloyees geboren voor 1970” SELECTE.DNR, COUNT(E.ENR) FROMEMPLOYEE AS E WHEREE.BDATE < ‘ ’ GROUP BYE.DNR;
Voorbeeld Database ENRNAME BDATE DNR E1John D1 DNR=“D1”, E2Joe D1 COUNT(ENR)=3 E3Jack D1
algemene vorm queries(DML) Algemene vorm SQL query: SELECT FROM [WHERE ] [GROUP BY ] [HAVING ] [ORDER BY ]; volgorde evaluatie: 1. WHERE 2.GROUP BY 3.HAVING
voorbeeld query ( / )(DML) “Geef de namen en ENRs van employees die voor 1970 zijn geboren” SELECTE.NAME, E.ENR FROMEMPLOYEE AS E WHEREE.BDATE < “ ”; in tupelcalculus: { (e.name, e.enr) | EMPLOYEE(e) e.bdate < “ ” }
voorbeeld query ( )(DML) “Geef de namen van de dependents van Will” SELECTD.NAME FROMDEPENDENT AS D, EMPLOYEE AS E WHERED.ENR = E.ENR AND E.NAME = “Will”; in tupelcalculus: { (d.name) | DEPENDENT(d) e (EMPLOYEE(e) d.enr = e.enr e.name = “Will”) }
voorbeeld database SECRETARY NAME ENR BDATE ADDRESS TSPEED Sue E Singel Mary E Damrak SALESMAN NAME ENR BDATE ADDRESS LMT John E Rokin Joe E Nes ENGINEER NAME ENR BDATE ADDRESS SPECIAL Jack E NZVBW 13 electronics Jill E NZABW 15 software
voorbeeld query ( )(DML) “Geef voor iedere employee (= secretary, salesman of engineer) z’n ENR en naam” (SELECTSEC.ENR, SEC.NAME FROM SECRETARY AS SEC)tupelcalculus: UNION{ (e.enr, e.name) | (SELECT SAL.ENR, SAL.NAME SECRETARY(e) FROMSALESMAN AS SAL) SALESMAN(e) UNION ENGINEER(e) } (SELECT ENG.ENR, ENG.NAME FROMENGINEER AS ENG);
voorbeeld query ( )(DML) “Geef de ENRs en namen van de ongehuwde engineering- employees” (SELECTEMP.ENR, EMP.NAME FROMEMPLOYEE AS EMP, DEPARTMENT AS DPM WHEREEMP.DNR = DPM.DNR AND DPM.NAME = “engineering”) EXCEPT (SELECTEMP.ENR, EMP.NAME FROMEMPLOYEE AS EMP, DEPENDENT AS DPD WHEREEMP.ENR = DPD.ENR AND (DPD.REL = “husband” OR DPD.REL = “wife”);
voorbeeld query (alternatief 1)(DML) “Geef de ENRs en namen van de ongehuwde engineering- employees” SELECTEMP.ENR, EMP.NAME FROMEMPLOYEE AS EMP WHEREEMP.DNR IN (SELECTDPM.DNR FROMDEPARTMENT AS DPM WHEREDPM.NAME = “engineering”) AND EMP.ENR NOT IN (SELECTDPD.ENR FROMDEPENDENT AS DPD WHEREDPD.REL=“husband” OR DPD.REL=“wife”);
voorbeeld query (alternatief 2)(DML) “Geef de ENRs en namen van de ongehuwde engineering- employees” SELECTEMP.ENR, EMP.NAME FROMEMPLOYEE AS EMP WHEREEXISTS (SELECTDPM.DNR FROMDEPARTMENT AS DPM WHEREDPM.NAME = “engineering” AND DPM.DNR = EMP.DNR) AND NOT EXISTS (SELECTDPD.ENR FROMDEPENDENT AS DPD WHEREDPD.REL=“husband” OR DPD.REL=“wife” AND DPD.ENR = EMP.ENR);
voorbeeld query (alternatief 2) “Geef de namen en E#’s van de ongehuwde engineering- employees” tupelcalculus: { (e.name, e.E#) | EMPLOYEE(e) dpm (DEPARTMENT(dpm) dpm.name = “engineering” dpm.D# = e.D#) dpd (DEPENDENT(dpd) (dpd.rel = “husband” dpd.rel = “wife”) dpd.E# = e.E#) }
voorbeeld query (alternatief 3)(DML) “Geef de ENRs en namen van de ongehuwde engineering- employees” SELECTEMP.ENR, EMP.NAME FROMEMPLOYEE AS EMP, DEPARTMENT AS DPM WHEREDPM.NAME = “engineering” AND DPM.DNR = EMP.DNR AND NOT EXISTS (SELECTDPD.ENR FROMDEPENDENT AS DPD WHEREDPD.REL=“husband” OR DPD.REL=“wife” AND DPD.ENR = EMP.ENR); probeer waar mogelijk “platte” queries te formuleren
voorbeeld database PROJECT JNRNAME J1build-intranet J2market-research WORKS_ON EMPLOYEEENRJNR ENRNAME BDATE DNR E2J1 E1John D1 E3J1 E2Joe D1 E3J2 E3Jack D1 E4J2 E4Will D2 E5J2 E5Bridget D2
voorbeeld query ( )(DML) “Geef de ENRs van de employees die werken aan alle projecten” algebra: WORKS_ON jnr PROJECT domeincalculus: { (e) | j (PROJECT(jnr: j) WORKS_ON(enr: e, jnr: j)) } tupelcalculus: { (e.enr) | EMPLOYEE(e) j (PROJECT(j) w (WORKS_ON(w) w.enr = e.enr w.jnr = j.jnr)) }
voorbeeld query ( )(DML) probleem: SQL heeft geen oplossing: herschrijf in query naar { (e.enr) | EMPLOYEE(e) j (PROJECT(j) w (WORKS_ON(w) w.enr = e.enr w.jnr = j.jnr)) } { (e.enr) | EMPLOYEE(e) j (PROJECT(j) w (WORKS_ON(w) w.enr = e.enr w.jnr = j.jnr)) } { (e.enr) | EMPLOYEE(e) j (PROJECT(j) w (WORKS_ON(w) w.enr = e.enr w.jnr = j.jnr)) }
voorbeeld query ( )(DML) “Geef de ENRs van de employees die werken aan alle projecten” SELECTE.ENR FROMEMPLOYEE AS E WHERENOT EXISTS (SELECTJ.JNR FROMPROJECT AS J WHERENOT EXISTS (SELECT* FROMWORKS_ON AS W WHEREW.ENR = E.ENR AND W.JNR = J.JNR));
voorbeeld complexe queries(DML) “Geef de namen en adressen van alle eventuele paren (d.w.z. personen van tegenovergesteld geslacht die binnen elkaars gewenste leeftijdscategorie vallen)” SELECTM.NAAM, M.ADRES, V.NAAM, V.ADRES FROMZOEKENDE AS M, ZOEKENDE AS V WHEREM.GESL = “M” AND V.GESL=“V” AND M.MINJ <= V.GJAAR AND V.GJAAR <= M.MAXJ AND V.MINJ <= M.GJAAR AND M.GJAAR <= V.MAXJ;
voorbeeld complexe queries(DML) NAAM ADRESNAAMADRES Teun Nes 30 TruusAmstel 80 Teun Nes 30 BepRokin 42 WimSingel 23 TruusAmstel 80 WimSingel 23 BepRokin 42 SjonDamstr 9 AnitaNZVBW 18
voorbeeld complexe queries (null-waarden) ZOEKENDE NAAM ADRES GESL GJAARMINJ MAXJ Teun Nes 30 M null Wim Singel 23 M Sjon Damstr 9 M Truus Amstel 80 V null Bep Rokin 42 V Anita NZVBW 18 V Kan Teun aan Bep gekoppeld worden? geldt (1950 <= null) AND (null <= 1960) ? geldt dan misschien ((1950 <= null) AND (null <= 1960)) ? Antwoord: 2x nee
voorbeeld complexe queries (null-waarden) ZOEKENDE NAAM ADRES GESL GJAARMINJ MAXJ Teun Nes 30 M null Wim Singel 23 M Sjon Damstr 9 M Truus Amstel 80 V null Bep Rokin 42 V Anita NZVBW 18 V (geef de mannen en vrouwen (n+a) met hetzelfde geboortejaar) SELECTM.NAAM, M.ADRES, V.NAAM, V.ADRES FROMZOEKENDE AS M, ZOEKENDE AS V WHEREM.GESL = ‘M’ AND V.GESL = ‘V’ AND M.GJAAR = V.GJAAR;
voorbeeld complexe queries (null-waarden) ZOEKENDE NAAM ADRES GESL GJAARMINJ MAXJ Teun Nes 30 M null Wim Singel 23 M Sjon Damstr 9 M Truus Amstel 80 V null Bep Rokin 42 V Anita NZVBW 18 V (geef de zoekenden (n+a) met een onbekend geboortejaar) SELECTZ.NAAM, Z.ADRES FROMZOEKENDE AS Z WHEREZ.GJAAR IS NULL;
SQL null-waarden(DML) SQL gebruikt in feite een driewaardige logica (true / false / unknown) alle vergelijkingen met null leveren unknown op (behalve IS) rekenregels logica: t u = ut u = t f u = ff u = u u u = uu u = u u = u alleen tupels waarvoor de expressie true is (en niet unknown of false) worden geselecteerd
voorbeeld complexe queries (DML) DRAAITFAN_VAN STATIONARTIESTPERSOONARTIEST CountryCarpenters JanOP CountryParton PietMeeuwis NoordzeeHazes JoostBorsato NoordzeeBorsato JoostCarpenters NoordzeeMeeuwis Radio10MeeuwisLUISTERT_NAAR Radio10ElvisPERSOONSTATION Radio10Abba JanRadio10 PietNoordzee JoostRadio10 JoostNoordzee
voorbeeld complexe queries(DML) “Geef de artiesten die gedraaid worden op de stations waar Joost naar luistert” SELECTD.ARTIEST FROMDRAAIT AS D, LUISTERT_NAAR AS L WHERED.STATION = L.STATION AND L.PERSOON = “Joost”; tupelcalculus: { (d.artiest) | DRAAIT(d) l (LUISTERT_NAAR(l) l.station = d.station l.persoon = “Joost”) }
voorbeeld complexe queries(DML) “Geef de fans van artiesten die nergens gedraaid worden” SELECTF.PERSOON FROMFAN_VAN AS F WHERENOT EXISTS (SELECTD.STATION FROMDRAAIT AS D WHERED.ARTIEST = F.ARTIEST); tupelcalculus: { (f.persoon) | FAN_VAN(f) d (DRAAIT(d) d.artiest = f.artiest) }
voorbeeld complexe queries(DML) “Geef de personen die tenminste naar ieder radiostation luisteren waar Piet ook naar luistert (eventueel ook nog naar andere stations)” oefening voor thuis (niet verplicht)
Voorbeeld complexe queries(DML) “Geef de personen die tenminste naar ieder radiostation luisteren waar Piet ook naar luistert (eventueel ook nog naar andere stations)” SELECTL1.PERSOON FROMLUISTERT_NAAR AS L1 WHERENOT EXISTS (SELECTLPIET.STATION FROMLUISTERT_NAAR AS LPIET WHERELPIET.PERSOON = “PIET” AND NOT EXISTS (SELECT* FROMLUISTERT_NAAR AS L2 WHEREL2.PERSOON = L1.PERSOON AND L2.STATION = LPIET.STATION));
ANSI/SPARC architectuur
create view(VDL) “Creëer een view met per department-name het aantal employees en hun gemiddelde geboortedatum” CREATE VIEW DEPARTMENT_OVERVIEW ASSELECT D.NAME, COUNT(E.ENR), AVG(E.BDATE) FROMDEPARTMENT AS D, EMPLOYEE AS E WHERED.DNR = E.ENR GROUP BYD.NAME; view implementatie: query modification of view materialization niet alle views / view attributen zijn updatable
constraints (1/2)(DDL) CREATE DOMAIN REL_DOMAIN AS VARCHAR(7) CHECK (REL_DOMAIN = “husband” OR REL_DOMAIN = “wife” OR REL_DOMAIN = “son” OR REL_DOMAIN = “daughter”); CREATE DOMAIN BUDGET_DOMAIN AS INT CHECK (BUDGET_DOMAIN >= 0 AND BUDGET_DOMAIN <= );
constraints (2/2)(DDL) CREATE ASSERTION NO_EMPTY_DEPARTMENTS CHECK (NOT EXISTS (SELECT* FROMDEPARTMENT AS D WHERENOT EXISTS (SELECT* FROMEMPLOYEE AS E WHEREE.DNR = D.DNR)));
Thuis nalezen: hoofdstuk 8 + aanvullingen hoofdstuk 8