11.4.2010je to krasa!15Databázové systémyBI-DBSB131 (zimní 2013/2014)středa 14:30, lichý týden, paralelka XYZMichal Valentavalentavalenta@fit.cvut.cz
Prohlašuji, že jsem svou semestrální práci vypracoval nesamostatně. Všechny zdroje, ze kterých jsem čerpal, nejsou uvedeny v části Odkazy.
Plavební společnostPopisPlavební společnost poskytuje tři typy služeb: plavby s průvodcem (na objednávku zákazníka), rezervace (a následné půjčení) lodi zákazníkovi a dále pokrývá pravidelné linky lodní a autobusové dopravy.Projekt je zadán a modelován tak, aby obsahoval všechny typy entit a vztahů.Požadovaný rozsah pro semestrální práci je 7 až 15 entit. Jednoduché dekompozice vztahu M:N bez atributů se nepočítají.Pravidelné linky jsou pokryty buď lodí nebo autobusem.Autobusy i lodě jsou ve vlastnictví firmy, proto je třeba sledovat, kde jsou umístěny. Firma používá pojem "zázemí", které má svůj identifikátor a adresu. Zázemí je buď přístaviště (evidujeme povinný počet kotvišť a nepovinně počet opravných doků) nebo depo (evidujeme nepovinně počet stání a úroveň možných oprav). Každý autobus má své depo, každá loď má nejvýše jedno přístaviště. V přístavišti může být více lodí, v depu více autobusů. Pokrytí pravidelných linek je organizováno následovně: linka má identifikátor, start a cíl. Po lince může jet více spojů. Spoj má navíc časový údaj, kdy je realizován. Firma pak zajišťuje pokrytí jednotlivých spojů v konkrétní den a to buď lodí a nebo autobusem.Kromě pravidelných spojů poskytuje firma též rezervaci lodí svým zákazníkům na konkrétní datum a nebo nabízí tzv. plavby s průvodcem.Firma si eviduje své zákazníky (ID, příjmení, jméno, adresa a kredit). Dále si eviduje námořníky, kteří pro ni pracují. U námořníků se vyžaduje evidence jména, věku, hodnosti a platu.Námořníkům firma eviduje kalendáře, kde mají vyznačeny své závazky. Závazkem rozumíme buď plavbu s průvodcem a nebo pokrytí nějakého pravidelného spoje. Závazek se vztahuje vždy na časový interval (od, do). Pro každou plavba s průvodcem je nutné evidovat zákazníka, loď a příslušný časový interval (závazek) v kalendáři námořníka, který je za plavbu zodpovědný.Z provozních důvodů platí ještě tato omezení: loď nemůže pokrývat žádný spoj ve dnech, na které má rezervaci nebo je na plavbě s průvodcem, není možné, aby si zákazník na jeden den rezervoval loď a zároveň měl naplánovanou plavbu s průvodcem, plavba s průvodcem a pokrytí nějakého spoje musí být naplánováno v kalendáři příslušného námořníka, tyto činnosti se nemohou překrývat. TECHNOLOGIESemestrální práce je z důvodu zachování jednotného vzhledu a pohodlného zpracování bez nároku na speciální SW založena na technologii XML. Pro práci vám stačí: - libovolný textový editor (takový, který zvýrazňuje formátování XML je výhodou - KWrite, PSPad, Eclipse, Netbeans, ...) - pro provedení kontoroly kompletnosti dokumentace (validita XML dokumentu) doporučujeme opensource utilitu xmllint - xmllint main.xml ... provede kontorlu, že soubor main.xml je syntakticky dobře uzávorkován (well-formed) - xmllint --dtdvalid sproject.dtd main.xml ... provede kontrolu, že soubor vyhovuje specifikaci předepsané v sproject.dtd (valid) - pro vytvoření požadovaného sqlscriptu (queries.sql) opensource utilitu xsltproc - xsltproc make_sql_queries_script.xsl main.xml >queries.sql ... ze souboru main.xml vyrobí požadovaný skript s dotazy queries.sql - transformace main.xml souboru ve www prihlížeči je provedena automaticky díky meta-tagu xml-stylesheet v hlaviččce souboru main.xml (pokud to příslušný www prohlížeč umí) Pro "domácí/lokální ladění" (soubory sproject.dtd, sproject_html.xsl a sproject_html.css jsou v adresáři společně s main.xml) doporučujeme důsledně používat firefox. A také se důsledně držet kódování UTF-8 Datový modelDiskuse: Diskuse smyček nebo konstatování, že smyčky nejsou je povinnáSchéma obsahuje smyčku "zakaznik - rezervace - lod plavba_s_pruvodcem - zakaznik". Její nebezpečí řeší přidaná integritní omezení IO1 a IO2.
Opticky je ve schématu další smyčka: kalendar_namornika - plavba_s_pruvodcem - lod - pokryti-kalendar_namornika, která by znamenala riziko, že konkrétní námořník může mít na jeden časový interval pokrytí pravidelného spoje a zároveň plavbu s průvodcem. Tato zdánlivá smyčka je však přestřižena díky výlučné účasti instance kalendar_namornika v jednom ze dvou vztahů k pokrytí nebo plavbě s průvodcem.Relační modelSekce "Relační model" je nepovinná.Diskuse:Relační model může být vhodnou pomůckou pro formulaci dotazů. Pracujete-li v SQLDeveloperu, máte jej "zadarmo".DotazyJména zelených lodi.LOD(BARVA = 'zelena')[JMENOL]SELECT *
FROM LOD L
WHERE L.LODID NOT IN (SELECT LODID
FROM REZERVACE);
SELECT DISTINCT JMENOL
FROM LOD
WHERE BARVA = 'zelená';
Jména zákazníků, kteří si rezervovali alespoň jeden modrý parník.{ZAKAZNIK * REZERVACE * LOD}(LTYP = 'parník')[JMENOZ]SELECT ZAKAZNIK.JMENOZ, zakaznik.prijmeni
FROM ZAKAZNIK JOIN REZERVACE USING(ZID)
JOIN LOD USING(LODID)
WHERE LOD.LTYP = 'parník' AND
LOD.barva= 'modrá';
POZOR na formátování SQL - důsledně používejte znak ";" za každým SQL příkazem - NEVKLÁDEJTE dovnitř SQL příkazu prázdné řádky (SQLDeveloper je vynechá, SQLPlus je chápe jako ukončení editace bufferu)Seznam typů lodí, které byly na plavbě s průvodcem.{LOD [LODID=ID_LOD] PLAVBA_S_PRUVODCEM }[LTYP]SELECT UNIQUE LTYP
FROM LOD L JOIN PLAVBA_S_PRUVODCEM PSP ON(L.LODID= PSP.ID_LOD);
Lodě (všechny atributy), které pokryly nějaké pravidelné spoje a byly také na některé plavbě s průvodcem.LOD <* POKRYTI
"mnozinovy prunik"
LOD <LODID=ID_LOD] PLAVBA_S_PRUVODCEM
SELECT L.*
FROM LOD L
WHERE L.LODID IN (SELECT LODID
FROM POKRYTI P)
INTERSECT
SELECT L.*
FROM LOD L
WHERE EXISTS (SELECT 1 FROM PLAVBA_S_PRUVODCEM
WHERE PLAVBA_S_PRUVODCEM.ID_LOD = L.LODID);
Lodě, (všechny atributy), které pokryly nějaký pravidelný spoj a nebo byly na plavbě s průvodcem.{LOD [L.LODID = P.LODID] POKRYTI}[LOD.LODID,JMENOL,LTYP,BARVA]
"sjednocení"
{LOD [L.LODID = P.ID_LOD] PLAVBA_S_PRUVODCEM}[LODID,JMENOL,LTYP,BARVA]
SELECT L.*
FROM LOD L JOIN POKRYTI P ON (L.LODID = P.LODID)
UNION
SELECT L.*
FROM LOD L JOIN PLAVBA_S_PRUVODCEM P ON (L.LODID = P.ID_LOD);
Lodě (všechny atributy), které nebyly rezervoványLOD "Levý přirozený antijoin" REZERVACE-- alternativa 1
SELECT *
FROM LOD L
WHERE L.LODID NOT IN (SELECT LODID
FROM REZERVACE);
-- alternativa 2
SELECT *
FROM LOD L
WHERE NOT exists (SELECT 1
FROM REZERVACE R
WHERE R.LODID = L.LODID);
-- alternativa 3
SELECT * FROM LOD
MINUS
SELECT L.* FROM LOD L JOIN REZERVACE R ON (R.LODID=L.LODID);Typy lodí, které pokrývají pouze pravidelné spoje. {LOD <* POKRYTI
\
LOD <LODID=ID_LOD] PLAVBA_S_PRUVODCEM
\
LOD <* REZERVACE
}[LTYP];
-- množinové operátory se ve výrazu vyhodnocují zleva doprava
Select distinct LTYP from
( Select L.*
FROM LOD L
where exists (select LODID from POKRYTI where pokryti.lodid = l.lodid)
MINUS
Select L2.*
FROM LOD L2
where exists (select ID_LOD from PLAVBA_S_PRUVODCEM where plavba_s_pruvodcem.id_lod=l2.lodid )
MINUS
Select L.*
FROM LOD L
where exists (select 1 from REZERVACE R where R.LODID=L.LODID)
);
Zákazníci (id_z, jméno), kteří si rezervovali každou zelenou loď. REZERVACE[ZID,LODID] "relační-dělení" LOD(BARVA='zelená')[LODID]
-- nebo (bez dělení)
T1:= LOD(BARVA='zelená')[LODID] x ZAKAZNIK[ZID] ... teoreticka rezervace
T2:= REZERVACE[LODID,ZID] ... uskutecnene rezervace
T3:= {T1\T2}[ZID] ... zakaznici, kteri si nerezervovali nekterou zelenou lod
T4:= REZERVACE[ZID]... zakaznici, kteri neco rezervovali
T5:= T4 "levy antijoin" T3 ... zakaznici, kteri rezervovali vsechny zelene lodi
set termout on
set echo on
delete from rezervace
where zid in(6,7) and lodid in (select lodid from lod where barva='zelená');
commit;
-- ========================= Priklad 8 =============================
-- pripravna faze
set termout on
set echo on
delete from rezervace
where zid in(6,7) and lodid in (select lodid from lod where barva='zelená');
commit;
-- Zakazniky (id_z, jmeno), kteri si rezervovali kazdou zelenou lod
-- REZERVACE[ZID,LODID] DIV LOD(BARVA='zelená')[LODID]
--
-- T1:= LOD(BARVA='zelená')[LODID] x ZAKAZNIK[ZID] ... všechny možné rezervace
-- T2:= LOD(BARVA='zelená')*> REZERVACE[LODID,ZID] ... uskutečněné rezervace zelených lodí
-- T3:= {T1\T2}[ZID] ... zákazníci, kteří si nerezervovali některou zelenou loď
-- T4:= T1[ZID] ... zákazníci, kteří rezervovali některou zelenou loď
-- T5:= T4 !<* T3 ... zákazníci, pro které neplatí, že si nerezervovali některou zelenou loď
WITH
T1 AS (SELECT unique LODID,ZID
FROM
(select lodid from LOD WHERE BARVA = 'zelená' ) CROSS JOIN ZAKAZNIK
),
T2 AS (SELECT UNIQUE LODID,ZID
FROM REZERVACE
where exists (select *
from lod
WHERE lod.barva='zelená' and lodid=REZERVACE.LODID)
),
T31 AS (SELECT * FROM T1 MINUS SELECT * FROM T2),
T32 AS (SELECT UNIQUE ZID FROM T31),
T4 AS (SELECT UNIQUE ZID FROM T1),
T5 AS (SELECT * From T4 Where T4.ZID Not In (Select ZID From T32))
Select *
From T5 Join zakaznik Using(ZID);
-- jednodušší zápis
WITH
T1 AS (SELECT unique LODID,ZID
FROM LOD CROSS JOIN ZAKAZNIK
WHERE BARVA = 'zelená' ),
T2 AS (SELECT UNIQUE LODID,ZID
FROM REZERVACE join lod using(lodid)
WHERE lod.barva='zelená'),
T31 AS (SELECT * FROM T1 MINUS SELECT * FROM T2),
T32 AS (SELECT UNIQUE ZID FROM T31),
T4 AS (SELECT UNIQUE ZID FROM T1),
T5 AS (SELECT *
From T4
Where T4.ZID Not In (Select ZID
From T32))
Select *
From T5 Join zakaznik Using(ZID);
-- dotaz vybral malo dat?
-- Pridejme testovaci data:
--
-- rezervujme zakaznikovi 7 vsechny zelene lodi:
insert into REZERVACE (LODID,ZID,DATUM_RES)
select lodid,7,to_date('01.01.01','DD.MM.RR')
from lod
where barva='zelená';
-- rezervujme zakaznikovi cislo 6 vsechny zelene lodi:
insert into REZERVACE (LODID,ZID,DATUM_RES)
select lodid,6,to_date('01.01.01','DD.MM.RR')
from lod
where barva='zelená';
commit;
--------------------------------------------
WITH
T1 AS (SELECT unique LODID,ZID
FROM LOD CROSS JOIN ZAKAZNIK
WHERE BARVA = 'zelená' ),
T2 AS (SELECT UNIQUE LODID,ZID
FROM REZERVACE join lod using(lodid)
WHERE lod.barva='zelená'),
T31 AS (SELECT LODID,ZID
FROM T1 MINUS SELECT LODID,ZID FROM T2),
T32 AS (SELECT UNIQUE ZID FROM T31),
T4 AS (SELECT UNIQUE ZID FROM T1),
T5 AS (SELECT ZID
From T4
Where T4.ZID Not In (Select ZID
From T32)
)
Select *
From T5 Join zakaznik Using(ZID);
--
-- --------- SQL umoznuje i toto reseni: -------
-- vyber zákazníky, pro které počet jimi rezervovaných zelených lodí se rovná celkovému počtu zelených lodí
select *
from zakaznik Z
where (Select count(DISTINCT LODID)
From REZERVACE R Join lod using(lodid)
Where R.ZID = Z.ZID and barva='zelená')
=
(Select count(*)
From LOD
where barva='zelená');
-- --------- nebo toto reseni pomocí dvojité negace: ---------
-- Vyber zákazníky, pro něž nexistuje zelená loď, kterou by neměli rezervovanou
select *
from zakaznik Z
where not exists
(Select LODID
From LOD
where barva='zelená'
MINUS
Select DISTINCT LODID
From REZERVACE R Join lod using(lodid)
Where R.ZID = Z.ZID and barva='zelená'
);
-- --------- nebo toto reseni pomocí dvojité negace: ---------
-- Vyber zákazníky, pro něž nexistuje zelená loď, pro kterou by neexistovala rezervace dané zelené lodi pro daného zákazníka
select *
from zakaznik Z
where not exists
(Select LODID
From LOD L
where barva='zelená' and
not exists ( Select LODID
From REZERVACE R
Where R.ZID = Z.ZID and R.LODID=L.LODID
)
);
--------------- kontrola, zkouska vysledku -----------------------------
-- Nasledujici 3 dotazy musi vratit stejne mnoziny lodi:
-- {Seznam zelenych lodi, ktere si rezervoval zakaznik zid=6}
-- {Seznam zelenych lodi, ktere si rezervoval zakaznik zid=7}
-- {Seznam vsech lodi se zelenou barvou}
SELECT LODID, JMENOL, LTYP, BARVA, POCET_MIST
FROM LOD
WHERE BARVA='zelená';
--
SELECT LOD.LODID
FROM REZERVACE INNER JOIN LOD ON LOD.LODID = REZERVACE.LODID
WHERE LOD.BARVA = 'zelená'
AND REZERVACE.ZID = 6;
--
SELECT LOD.LODID
FROM REZERVACE INNER JOIN LOD ON LOD.LODID = REZERVACE.LODID
WHERE LOD.BARVA = 'zelená'
AND REZERVACE.ZID = 6;
--
--------------- úklid -----------------------------
delete from rezervace
where zid in(6,7) and lodid in (select lodid from lod where barva='zelená');
commit;
Testovací data pro dotaz 8: Rezervuj zákazníkům 6 a 7 každou zelenou loď.
set termout on
set echo on
delete from rezervace
where zid in(6,7) and lodid in (select lodid from lod where barva='zelená');
commit;
-- rezervujme zakaznikovi 7 vsechny zelene lodi:
insert into REZERVACE (LODID,ZID,DATUM_RES)
select lodid,7,to_date('01.01.01','DD.MM.RR')
from lod
where barva='zelená';
-- rezervujme zakaznikovi cislo 6 vsechny zelene lodi:
insert into REZERVACE (LODID,ZID,DATUM_RES)
select lodid,6,to_date('01.01.01','DD.MM.RR')
from lod
where barva='zelená';
commit;
--------------------------------------------
Zkouška výsledku pro dotaz 8:
Které zelené lodi si rezervoval zákazník 6.
Které zelené lodi si rezervoval zákazník 7. Jsou všechny?
set termout on
--------------- kontrola, zkouška -----------------------------
/*
Předpokládejme, že dotaz vybral zákazníky s ZID=6 a ZID=7.
Potom následující 3 dotazy musí vrátit stejné množiny lodí:
{Seznam zelených lodí, ktere si rezervoval zákazník zid=6}
{Seznam zelených lodí, které si rezervoval zákazník zid=7}
{Seznam všech lodí se zelenou barvou}
*/
SELECT LOD.LODID
FROM REZERVACE INNER JOIN LOD ON LOD.LODID = REZERVACE.LODID
WHERE LOD.BARVA = 'zelená'
AND REZERVACE.ZID = 6;
--
SELECT LOD.LODID
FROM REZERVACE INNER JOIN LOD ON LOD.LODID = REZERVACE.LODID
WHERE LOD.BARVA = 'zelená'
AND REZERVACE.ZID = 7;
--
SELECT LODID, JMENOL, LTYP, BARVA, POCET_MIST
FROM LOD
WHERE BARVA='zelená';
--------------------------------------------
Dvojice zákazníků, kteří bydlí na stejné adrese.{{ZAKAZNIK[ADRESA -> ADR1,ZID-> ZID1,JMENOZ-> JMENO1, PRIJMENI-> PRIJMENI1]}
[ADR1=ADR2 AND ZID1 < ZID2]
{ZAKAZNIK[ADRESA -> ADR2,ZID-> ZID2, JMENOZ-> JMENO2,PRIJMENI-> PRIJMENI2]}
}[ZID1,JMENO1,PRIJMENI1,ZID2,JMENO2,PRIJMENI2]
Select cast(Z1.zid||' '||Z1.jmenoz||' '||Z1.prijmeni||' sousedí s '||
Z2.zid||' '||Z2.jmenoz||' '||Z1.prijmeni as varchar(60)) as sousede
From zakaznik Z1 Join zakaznik Z2 On (Z1.adresa=Z2.adresa and
Z1.zid < Z2.zid);
Seznam námořníků. U každého uveďte, kolika plaveb s průvodcem se účastnil
-- Seznam námořníků. U každého uveďte, kolika plaveb s průvodcem se účastnil.
select NID, JMENON, VEK, HODNOST, PLAT,
(select COUNT(*)
from PLAVBA_S_PRUVODCEM PSP
where PSP.NID = N.NID) as pocet_plaveb_s_průvodcem
FROM NAMORNIK N;
Cekový počet typů lodí, počet různých typů lodí a celkový počet míst na všech lodích.Select count(distinct ltyp) pocet_typu_lodi
, count(distinct barva) pocet_ruznych_barev
, sum(pocet_mist) celkovy_pocet_mist
From LOD;
Lodníci, kteří byli na plavbě s průvodcem méně, než 4 krát.Select *
From namornik N
Where (Select count(*)
From PLAVBA_S_PRUVODCEM PSP
Where N.nid = PSP.nid) < 4;
-- alternativni reseni
Select nid,N.JMENON,N.VEK,N.HODNOST,N.PLAT
From namornik N Left Outer join PLAVBA_S_PRUVODCEM P Using(nid)
GROUP BY nid, N.JMENON, N.VEK, N.HODNOST, N.PLAT
Having count(ID_LOD) < 4;
Lodníci, kteří pokryli méně než 3 různé pravidelné linky včetně těch, kteří nepokryli žádnou.Select N.*,
(Select count(DISTINCT LID)
From pokryti P
Where P.nid = N.nid) pocet_ruznych_linek
From namornik N
Where (Select count(DISTINCT LID)
From pokryti P
Where P.nid = N.nid) < 3;
-- alternativni reseni
SELECT NID,N.JMENON,N.VEK,N.HODNOST,N.PLAT,COUNT(LODID)
FROM NAMORNIK N Left Outer Join POKRYTI P Using (Nid)
GROUP BY NID,N.JMENON,N.VEK,N.HODNOST,N.PLAT
Having count (LODID) < 3;
Pro každého lodníka počet jeho plaveb s průvodcem.Select N.*,
(Select count(*)
From PLAVBA_S_PRUVODCEM PSP
Where N.nid = PSP.nid) pocet_PSP
From namornik N;
-- alternativa
Select nid,N.JMENON,N.VEK,N.HODNOST,N.PLAT,
count(ID_LOD) pocet_PSP
From namornik N Left Outer join PLAVBA_S_PRUVODCEM P
Using(nid)
GROUP BY nid, N.JMENON, N.VEK, N.HODNOST, N.PLAT;
Jména lodníků mladších 40 let, kteří mají za sebou alespoň 3 plavby s průvodcem na lodi typu klipr. Výstup bude seřazen dle jmen lodníků.Select N.nid,N.JMENON
From Namornik N
Where (Select count(*)
From PLAVBA_S_PRUVODCEM PSP Join LOD L On(LODID= ID_LOD)
Where PSP.nid = N.nid
and L.Ltyp ='klipr'
) >=3
and N.vek <40
order by N.JMENON desc;
-- alternativa
Select nid,N.JMENON
From Namornik N Join PLAVBA_S_PRUVODCEM PSP Using (nid)
Join lod L On (LODID= ID_LOD)
Where L.Ltyp ='klipr' and N.vek <40
Group By nid,N.JMENON
having count(*) >= 3
order by N.JMENON desc;
Námořníkům, kteří mají za sebou alespoň 4 pokrytí spoje zvedněte plat o 15%.Update namornik N
Set plat = plat * 1.15
where (Select count (lodid)
From pokryti P
Where P.nid = N.nid) > 4;
K tabulce LODNIK přidám sloupec pocet_plaveb_s_pruvodcem a provedu jednorázový dopočet hodnot tohoto sloupce.-- pridani sloupce
Alter Table NAMORNIK
Add (pocet_plaveb_s_pruvodcem integer Default 0);
-- dopocitani
Update namornik N
Set pocet_plaveb_s_pruvodcem = (Select count(*)
From PLAVBA_S_PRUVODCEM PSP
Where PSP.nid=N.nid);
Commit;
-- overeni
select *
from namornik;
-- uklid
alter table namornik drop column pocet_plaveb_s_pruvodcem;
select *
from namornik;
Zákazníci, kteří si rezervovali každý parník s počtem míst větším než 150.
-- REZERVACE[zid,lodid] "deleno" LOD(ltyp='parník' and POCET_MIST > 150)[lodid];
-- T1 := REZERVACE[zid,lodid]
-- T2 := ZAKAZNIK[zid] X LOD(LTYP= 'parník'and POCET_MIST > 150)[LID]
-- T3 := {T2 \ T1}[zid]
-- T4 := {REZERVACE[ZID] \ T3} * ZAKAZNIK
set echo on
-- podivejme se na data jmenovatele
select * from zakaznik;
select LODID from lod where ltyp='parník' and POCET_MIST > 150;
-- jak vidno, budeme dělit prázdnou relací
with
T1 as (select distinct zid,lodid from REZERVACE)
, T2 as (select zid,lodid from
(Select ZID from ZAKAZNIK) cross join
(select LODID from lod where LTYP= 'parník'and POCET_MIST > 150)
)
, T3 as (select zid,lodid from T2 minus select zid,lodid from T1)
, T4 as ( select distinct ZID from rezervace MINUS select distinct zid from T3 )
Select *
from zakaznik Z natural join T4;
Vytvoření pohledu se seznamem spojů, u nichž budou podrobnosti jejich linek.create or replace view vspoj as
select lid,linka.strt,linka.cil,
spoj.spid, spoj.scas
from spoj natural join linka
order by lid,spoj.scas;
-- vyber vsechny spoje, ktere by jely dnes po 12. hodine
select strt, cil, trunc(current_date) + scas as kdy
from vspoj
where trunc(current_date) + scas > trunc(current_date) + INTERVAL '12' HOUR(2)
order by scas;
Kteří lodníci sloužili na jednotlivých lodích?select distinct lod.lodid,n.nid
From lod
left outer join (SELECT distinct NID, LODID FROM POKRYTI
union
SELECT unique NID, id_lod FROM PLAVBA_S_PRUVODCEM) A
on (lod.lodid=A.lodid)
right outer join namornik N on (A.nid=N.nid)
order by lodid, nid;
Seznam rezervací včetně lodí, které nebyly rezervovány a zákazníků, kteří si nic nerezervovali.SELECT REZERVACE.DATUM_RES,
ZAKAZNIK.ZID,
ZAKAZNIK.JMENOZ,
ZAKAZNIK.PRIJMENI,
ZAKAZNIK.CREDITLIMIT,
ZAKAZNIK.ADRESA,
LOD.LODID,
LOD.JMENOL,
LOD.BARVA,
LOD.LTYP,
LOD.POCET_MIST
FROM ZAKAZNIK LEFT OUTER JOIN REZERVACE ON ZAKAZNIK.ZID = REZERVACE.ZID
FULL OUTER JOIN LOD ON LOD.LODID = REZERVACE.LODID
order by datum_res, zakaznik.prijmeni,zakaznik.jmenoz,lod.jmenol;Seznam linek, které jsou pokryty pouze autobusem SPZ101-- Seznam linek, které jsou pokryty pouze autobusem SPZ101
SELECT distinct LINKA.LID, STRT,CIL
FROM LINKA
INNER JOIN SPOJ ON LINKA.LID = SPOJ.LID
INNER JOIN POKRYTI ON SPOJ.LID = POKRYTI.LID
AND SPOJ.SPID = POKRYTI.SPID
INNER JOIN AUTOBUS ON AUTOBUS.INV_CISLO = POKRYTI.INV_CISLO
AND SPZ='SPZ101'
MINUS
SELECT distinct LINKA.LID, STRT,CIL
FROM LINKA
INNER JOIN SPOJ ON LINKA.LID = SPOJ.LID
INNER JOIN POKRYTI ON SPOJ.LID = POKRYTI.LID
AND SPOJ.SPID = POKRYTI.SPID
INNER JOIN AUTOBUS ON AUTOBUS.INV_CISLO = POKRYTI.INV_CISLO
AND SPZ != 'SPZ101';
Seznam námořníků, kteří jsou volní dne 23.09.2013 od 8 do 14 hod.
alter session set nls_date_format = 'dd.mm.yyyy hh24:mi';
select *
from namornik
where nid in ( select distinct nid
from kalendar_namornika
where od not in ('23.09.2013 08:00', '23.09.2013 14:00')
);
Seznam lodí, které jsou volné dne 23.09.2013 od 8 do 14 hod. a mají kapacitu od 10 do 25 míst.
alter session set nls_date_format = 'dd.mm.yyyy hh24:mi';
select distinct lodid
from lod l1
where lodid not in (select lodid
from rezervace
where datum_res = '23.09.2013')
and not exists (select lodid
from pokryti p
where l1.lodid = p.lodid
and p.DATUM_POKRYTI = '23.09.2013'
and ( p.od in ('23.09.2013 08:00', '23.09.2013 14:00')
or p.do in ('23.09.2013 08:00', '23.09.2013 14:00')
)
)
and l1.pocet_mist in (10,25);
Přidejte novou plavbu s průvodcem pro zákazníka s příjmením Scott a jménem Scott na 23.09.2013 od 8 do 14 hod.Nasaďte na to loď, která je na tu dobu volná a má kapacitu 10 až 25 míst.Nasaďte na to kteréhokoliv námořníka, který je na tuto dobu volný.alter session set nls_date_format = 'dd.mm.yyyy hh24:mi';
-- set autocommit off
-- nejdrive je nutne vyplnit kalendar namornika
INSERT
INTO KALENDAR_NAMORNIKA (NID,OD,DO)
VALUES( (select nid
from kalendar_namornika
where od not in ('23.09.2013 08:00', '23.09.2013 14:00')
and rownum =1
),
'23.09.2013 08:00',
'23.09.2013 14:00'
);
-- zaplanovani plavby
INSERT
INTO PLAVBA_S_PRUVODCEM( NID,OD,DO,ID_LOD,ZID)
VALUES ( (select nid
from kalendar_namornika
where od ='23.09.2013 08:00' and do= '23.09.2013 14:00'
and rownum=1
),
'23.09.2013 08:00',
'23.09.2013 14:00',
( select distinct lodid
from lod l1
where lodid not in ( select lodid
from rezervace
where datum_res = '23.09.2013')
and not exists ( select lodid
from pokryti p
where l1.lodid = p.lodid
and p.DATUM_POKRYTI = '23.09.2013'
and ( p.od in ('23.09.2013 08:00', '23.09.2013 14:00')
or p.do in ('23.09.2013 08:00', '23.09.2013 14:00')
)
)
and l1.pocet_mist in (10,25)
and rownum = 1
),
( SELECT ZID
FROM ZAKAZNIK
WHERE prijmeni='Scott' and jmenoz='Scott' and rownum=1
)
);
rollback;
Ad2d3pozitivní dotaz nad spojením alespoň dvou tabulek (Seznam kateder - id, název, jejichž učitelé učil/učili v předmětech, které garantuje katedra KKKK), („vyber seznam se jmény a adresami pacientů, kteří byli vyšetřováni Mudr. Čermákem“ )Bd6negativní dotaz nad spojením alespoň dvou tabulek (seznam semestrů - id, název, ve kterých NEzkoušel nikdo z katedry Zubních trhaček), („seznam se jmény a adresami pacientů, kteří nenavštívili lékaře Mudr. Čermáka“ )Cd7d22Vyber ty, kteří mají vztah POUZE k …(vyber seznam kateder učitelů, kteří učí/učili POUZE v letních semestrech), (# „seznam se jmény a adresami pacientů, kteří navštívili pouze Mudr. Čermáka ~ navštívili doktora Čermáka a nenavštívili žádného jiného lékaře)D1d8Vyber ty, kteří/které jsou ve vztahu se všemi - dotaz s univerzální kvantifikací (seznam učitelů - id, jmeno, prijmeni, titul, kteří přednášeli ve VŠECH semestrech počínaje zimním semestrem 2001/2002 až do letního semestru 2007/2008 včetně),(„seznam se jmény a adresami lékařů, které navštívíli VŠICHNI pacienti, kteří někdy navštívili Mudr. Čermáka“)D2d8b kontrola výsledku dotazu z kategorie D1, například jestliže dotaz {seznam učitelů, kteří přednášeli ve VŠECH semestrech počínaje zimním semestrem 2001/2002 až do letního semestru 2007/2008 včetně} vybere učitele „123 Michal Valenta“, tak kontrolní dotaz bude {{Seznam semestrů ze zadaného obodobí, ve kterých přednášel Michal Valenta} \ {Seznam všech semestrů ze zadaného období}} a ten musí vrátit prázdnou množinu F1d3spojení - JOIN ONF2d2spojení - NATURAL JOIN | JOIN USINGF3d8spojení - CROSS JOINF4d11polospojení (vnější) - LEFT | RIGHT OUTER JOINF5d21plné (vnější) spojení - FULL (OUTER) JOING1d8d23d24vnořený dotaz v klauzuli WHEREG2d18vnořený dotaz v klauzuli FROMG3d10vnořený dotaz v klauzuli SELECTG4d18d3vztažený vnořený dotaz (EXISTS | NOT EXISTS)H1d5množinové sjednocení - UNIONH2d6množinový rozdíl - EXCEPT nebo MINUS (v Oracle)H3d5množinový průnik - INTERSECTI1d11agregační funkce (count | sum | min | max| avg)I2d14 d15agregační funkce nad seskupenými řádky - GROUP BY (HAVING)Jd6 d8stejný dotaz ve třech různých formulacích SQLKd15všechny klauzule - SELECT FROM WHERE GROUP BY HAVING ORDER BYLd19pohled VIEWMd19dotaz nad pohledemNd8aPříkaz pro vložení množiny řádků - INSERT bez klauzule VALUES, např. Rezervuj zákazníkovi č. 6 v různých časech všechny zelené loděOd16UPDATE s vnořeným SELECT příkazemPd7DELETE s vnořeným SELECT příkazemV semestrálce se požaduje alespoň 25 SQL příkazů a alespoň 10 dotazů v relační algebře.SQL příkazů samozřejmě můžete mít více (jako v této semestrálce), je ale podstatné, abyste jiimi pokryli všechny kategorie ve výše uvedené tabulce.Samozřejmě tedy jeden dotaz může pokrýt více kategorií.SkriptyZdrojový soubor pro SQLDeveleper verze 3.2 - sqldev-sources.zip Před importem nutno rozbalit.Skript pro vytvoření databáze - create.sql .Skript pro vložení dat do databáze - insert.sqlPro efektivnější vkládádání dat většího množství - pokryti_bus_linek_data.zipStáhnu a rozbalím tento archivni soubor a extrahuji soubor pokryti_bus_linek_data.xlsV SQLDeveloper:- vyberu tabulku POKRYTI, klepnu na pravé tlačítko myši,- v lokální nabídce zvolím Import Data, spustí se průvodce, který mě povedeImport proběhl mnohem rychleji, než, kdybych měl data ve formátu insert scriptuSkript s SQL dotazy, který je možné přímo spustit - queries.sql.Soubor queries vřele doporučujeme vyrobit pomocí XSLT transformace "make_sql_queries_script.xsl".Lze použít libovolný XSLT procesor - například xsltproc, který je volně dostupný.Příslušné volání vypadá takto: xsltproc make_sql_queries_script.xsl main.xml >queries.sql Výsledný soubor "queries.sql" je vytvořen pro spuštění v nástroji SQLPlus a jeho výstupem je přímo požadovaný log soubor.POZOR na formátování SQL - důsledně používejte znak ";" za každým SQL příkazem - NEVKLADEJTE dovnitř SQL příkazu prázdné řádky (SQLDeveloper je vynechá, SQLPlus je chápe jako ukončení editace bufferu)Výstup předchozího skriptu - queries-log.html.Pokud jste použili trasformaci "make_sql_queries_script.xsl" a všechny dotazy máte bezchybně odladěné, je vytvoření tohoto souboru triviální.V prostředí SQLPlus spustíte pomocí příkazu "@" výše vytvořený soubor. SQL> @queries POZOR: nezapomeňte na správné nastavení proměnné shell: export NLS_LANG=american_america.utf8, jinak nebude správně zobrazené čeština.Pokud z nějakého důvodu nejste schopni použít cestu přes transformaci a sqlplus, lze log soubor s dokladem toho, že vaše SQL příkazy fungují a vrací rozumná data vytvořit alternativně (třeba pomocí snímků z SQLDevelopera).Tato cesta je samozřejmě mnohem pracnější!ZávěrNa svém prvním databázovém projektu jsem si osvojil základy práce s datovým modelářem, relační algebrou a SQL databází. Vzhledem k tomu, že se
jednalo o první pokus v tomto oboru, není výsledek optimální.Pokud bych měl stejný projekt dělat znovu byla by některá návrhová rozhodnutí na konceptuální i databázové úrovni jiná.Cílem semestrální práce však bylo zejména vyzkoušet si návrh struktury datového úložiště od specifikace až po implementaci v relačním databázovém stroji.
Tento cíl byl rozhodně splněn.Odkazy[1] Stránky předmětu BI-DBS - https://edux.fit.cvut.cz/courses/BI-DBS[2] J. Pokorný, M. Valenta: Databázové systémy. Česká technika - nakladatelství ČVUT. ISBN: 978-80-01-05212-9. 2013[3] Božena Němcová: Babička, vlastní náklad, ISBN: 123-45-67-86AB-C. 2013