OQL (Object Query Language) Michal Bartoš Filip Bureš
Obsah (1) ODMG Základní vlastnosti OQL Struktura dotazu Datové typy Práce s objekty Tvorba objektů
Objektová databáze Rozdíly oproti relační databázi: Data nejsou ukládána jako jednotlivé primitivní typy, ale jako objekty s vlastnostmi Lépe odpovídá lidskému chápání reálného světa Koresponduje s objektovými programovacími jazyky
ODMG Object Data Management Group Object Data Management Systems (ODMSs) Systémy podporující standardy ODMG Základní součásti ODMG specifikace Object Model Object Definition Language (ODL) Object Query Language Object Interchange Format (OIF) Programing Language Binding
Object model Vychází z Object Management Group (OMG) Jedná se o společný základ objektových prostředí Jazykově nezávislý Obsahuje: Abstraktní datové typy (ADT) Atributy, vazby Zapouzdření, dědičnost, polymorfismus Rozhraní, metody...
Object Definition Language Vychází z OMG Interface Definition Language (IDL) Definuje jednotlivé objekty a jejich vlastnosti v souladu s ODMG objektovým modelem Nezávislý na programovacím jazyce
Object Interchange Format Specifikační jazyk pro definici formátu uložení stavu ODMS Nezávislý na implementaci ODMS Obsahuje definice: Identifikátoru objektu Typového omezení Hodnoty atribut Vazby na jiný objekt
Základní vlastnosti OQL Vystavěno nad ODMG objektovým modelem, přebírá tedy typy definované v příslušném modelu Velmi blízké normě SQL-92, rozšířeno o konstrukce týkající se objektů Neobsahuje modifikační operátory jako SQL, modifikace objektů je prováděna prostřednictvím jejich metod OQL je funkcionální jazyk
Příklad objektového modelu (1) class Adresa { attribute string město; attribute string ulice; attribute short číslo_domu; }; class Osoba { attribute string jméno; attribute date datum_narození; attribute Osoba partner; attribute set<osoba> děti; attribute Adresa adresa; set<string> aktivity (); short věk (); };
Příklad objektového modelu (2) class Zaměstnanec (extent Osoba) { attribute int plat; attribute Firma zaměstnání; set<string> aktivity(); }; class Student (extent Osoba) { attribute int student_id; attribute string škola; attribute set<kurz> navštěvuje; set<string> aktivity(); }; class Firma { attribute string jméno; attribute set<zaměstnanec> zaměstnanci; }; class Kurz { attribute Zaměstnanec učí; };
Struktura dotazu Obdobná jako u SQL s ohledem na objektové rozšíření Operátory mohou být libovolně skládány, dokud odpovídají typové kontrole
Struktura dotazu (1) select [distinct] f(x 1,, x n, x n+1,, x n+p ) fromx 1 in e 1 (x n+1,, x n+p ) x 2 in e 2 (x 1, x n+1,, x n+p ) x n in e n (x 1,, x n-1, x n+1,, x n+p ) [where p(x 1,, x n, x n+1,, x n+p )] [order by f 1 (x 1,, x n, x n+1,, x n+p ),, f q (x 1,, x n, x n+1,, x n+p )]
Struktura dotazu (2) select [distinct] f(y 1,, y m, partition) from x 1 in e 1 (x n+1,, x n+p ) x 2 in e 2 (x 1, x n+1,, x n+p ) x n in e n (x 1,, x n-1, x n+1,, x n+p ) [where p(x 1,..., x n, x n+1, x n+p )] group by y 1 : g 1 (x 1,..., x n+p ),, y m : g m (x 1,..., x n+p ) [having h(y 1,, y m, partition)] [order by f 1 (y 1,, y m, partition),, f q (y 1,, y m, partition)]
Struktura dotazu - příklad Najděte jméno ulice s nejmenším průměrným platem zaměstnanců co v ní žijí. first(select ulice, prum_plat: avg(select e.plat from partition) from (select (Zaměstnanec)p from Osoby p where ma praci in p.aktivity) as e group by ulice: e.adresa.ulice order by prum_plat).ulice
Datové typy Typy objektů jsou přebírány z modelu Druhy kolekcí: Set pořadí vkládání nemá vliv, bez opakování Bag pořadí vkládání nemá vliv, s opakováním List prvky dle pořadí vkládání, s opakováním Array klasické pole Typy literálů: Atomický jedna základní hodnota Strukturovaný složený z atomických literálů Kolekce kolekce složena z literálů
Kompatibilita datových typů Definována rekurzivně: 1) T je kompatibilní s T 2) Je-li T kompatibilní s T', pak jsou i kolekce vzniklé z těchto typů kompatibilní (př.: set<t> a set<t'>) 3) Existuje-li T takové, že je nadtypem T' i T'', pak jsou T' a T'' kompatibilní Literály jsou kompatibilní pouze pokud obsahují stejnou hodnotu (kolekce musí být stejného typu a musí se shodovat všechny jejich hodnoty)
Přístup k položkám objektů Pro strukturované objekty Pomocí tečky nebo šipky (jsou ekvivalentní) př.: o.partner.adresa.město, kde o je typu Osoba Také zpřístupňuje metody objektu př.: o.věk, kde věk je metoda objektu Osoba Přístup na atribut nebo k metodě na neexistujícím objektu (tedy na hodnotě nil) má za výsledek vrácení speciální hodnoty UNDEFINED př.: o.partner.jméno, pokud o nemá partnera
Průchod prvků kolekce Pomocí dotazu (select) př.: select d.jméno from o.děti d kde o je typu Osoba a tedy o.děti je typu kolekce Alternativní způsoby zápisu: o.děti as d d in o.děti
Identifikace objektů Unikátní identifikátor (OID) Výběr přes rovnost atributu s literálem Pojmenovaný objekt Slouží jakožto přístupový bod do databáze Je potřeba odněkud dotaz začít (obdoba určení zdroje dat ve from klauzuli v SQL)
Získávání objektů z databáze Přímo přes pojmenovaný objekt Typicky jeden konkrétní objekt nebo kolekce př.: Ředitel pojmenovaný objekt typu Zaměstnanec Ředitel.partner partner pojmenovaného objektu typu Zaměstnanec, který je typu Osoba
Získávání objektů z databáze Získání objektů z DB pomocí select příkazu Vrací kolekci objektů Typ kolekce je: bag standardně set je-li použito klíčové slovo distinct list je-li výsledek setřízen použitím order-by
Tvorba objektů Konstruktor pojmenován stejně jako jméno typu objektu který tvoří Hodnoty atributů jsou předány jako parametry volání konstruktoru Atributy které nejsou nastaveny dostanou standardní hodnotu př.: Adresa(město: Praha, ulice: Dlouhá, ) struct(a: Novák, b: 10)
Tvorba objektů Tvorba objektu jako výsledku dotazu Příklady (předpokládám existenci pojmenovaného objektu Osoby obsahující kolekci všech Osob): typedef bag<osoba> Nov; Nov(select * from Osoby where jméno = Novák ) class detail {attribute string j; attribute Adresa a;}; typedef bag<detail> detaily; detaily(select detail(j: jméno, a: adresa) from Osoby where jméno = Novák )
Tvorba objektů Tvorba základních objektů a kolekcí: struct(jméno: Novák, věk: 10) set(1, 2, 3, 5) list(3, 4, 5) je stejný jako list(3..5) Zkrácený zápis pomocí.. lze použít i pro písmena bag(1, 2, 2, 3, 3, 3) array(3, 4, 2, 1, 1)
Operace nad kolekcemi typu list a array Získání jednoho konkrétního prvku: list(a, b, c, d) [1] b first(list(a, b, c, d)) a last(list(a, b, c, d)) d Získání podkolekce: list(a, b, c, d) [1:3] list(b, c, d) Spojení dvou kolekcí: list(a, b) + list(b, c) list(a, b, b, c)
Obsah (2) Kvantifikátory UNDEFINED Agregační funkce, Group by, Order by Pojmenované dotazy Skládání operátorů Polymorfismus Další konstrukce jazyka
Kvantifikátory Univerzální for all x in e 1 : e 2 true, false, UNDEFINED for all x in Studenti: x.student_id > 0 Existenční exists x in e 1 : e 2 true, false, UNDEFINED exists x in Doe.navštěvuje: x.učí.jméno= Turing exists(e) true, pokud v kolekci e existuje alespoň jeden prvek
Speciální hodnota Platí následující pravidla UNDEFINED is_undefined(undefined) je true Pokud podmínka ve where vrátí UNDEFINED bere se to jako by podmínka byla false UNDEFINED je platná hodnota při vytváření kolekcí nebo objektů UNDEFINED je platná hodnota pro agregační funkci count Výsledek ostatních operací, které mají jako operand UNDEFINED, je UNDEFINED
UNDEFINED (příklad) select e.adresa.město from Zaměstnanci e { Paříž, Praha, UNDEFINED } select e.adresa.město from Zaměstnanci e where is_defined(e.adresa.město) { Paříž, Praha } select e from Zaměstnanci e where is_undefined(e.adresa.město) Zaměstnanci, kteří nemají žádnou adresu
Agregační funkce Aplikují se na kolekce min, max, count, sum, avg max(select plat from Zaměstnanci) Lze aplikovat na číselné kolekce (integer, float) Pokud kolekce obsahuje UNDEFINED hodnotu, tak výsledek operace je UNDEFINED Vyjímku tvoří count count({ Praha, Paříž, UNDEFINED})
Group by operátor Rozdělí výsledek dotazu na množiny (partition) dle zadaných parametrů set<attributes, partition: bag<t>> V dotazu lze k jednotlivým množinám přistupovat pomocí klíčového slova partition select ulice, průměrný_plat: avg( select x.e.plat from partition x) from Zaměstnanci e group by ulice: e.adresa.ulice
Group by operátor Množiny můžeme tvořit za použití více atributů select * from Zaměstnanci e group by low: plat < 1000 medium: plat >= 1000 and plat < 10000 high: plat >= 10000
Group by operátor Pro modifikaci jednotlivých množin lze použít having select firma, průměrný_plat: avg(select x.e.plat from partition x) from Zaměstnanci e group by firma: e.zaměstnání.jméno having avg(select x.e.plat from partition x) > 30000 Dotaz vrací dvojice firma a průměrný plat zaměstnanců těchto firem, pokud je tento průměr vyšší než 30000
Order by operátor Slouží k setřídění výsledku dotazu select p from Osoby p order by p.věk, p.jméno
Pojmenované dotazy define, undefine Identifikátor dotazu musí být unikátní Pojmenované dotazy zustávají aktivní dokud nejsou přepsány nebo smazány define věk(string x) as select p.věk from Osoby p where p.jméno=x define novákovi() as select p from Osoby p where p.name= Novák
Skládání operátorů Operátory můžou být volně skládány, ale musí být dodrženy datové typy define Zaměstnanci() as select (Zaměstanec) p from Osoby p where má práci in p.aktivity
Skládání operátorů define mapa_platů() as select ulice, průměrný_plat:avg( select x.e.plat from partition x) from Zaměstnanci() e group by ulice: e.adresa.ulice define setříděná_mapa_platů() as select s from mapa_platů() s order by s.průměrný_plat first(setříděná_mapa_platů()).ulice
Skládání operátorů first(select ulice, průměrný_plat:avg( select e.plat from partition) from (select (Zaměstnanec) p from Osoby p where má prácí in p.aktivity) as e group by ulice: e.adresa.ulice order by průměrný_plat).ulice
Polymorfismus Filosofie polymorfismu v OQL je stejná jako u objektově orientovaných jazyků Objekt lze použít na místě kde lze použít jeho předka Konverze nastává automaticky je-li to třeba a je to možné
Pozdní vazba (Late binding) select p.aktivity from Osoby p Metoda aktivity má tři verze v závislostí nad jakým objektem je volána (Student, Zaměstnanec, Osoba) Pří zpracování dotazu je zavolána správná verze metody v závislosti na typu, který má zrovna zpracovávaná osoba p
Přetypování Správný typ kontrolován až během zpracování dotazu select ((Student)p).škola from Osoby p where přednášky in p.aktivity
Literály Objektové: nil Boolovské: false,true Znaky: 'a' Řetězce: řetězce Datum: date '1977-11-07' Čas: time '14:23:05.3' Timestamp: timestamp '1977-11-07 14:23:05.3' Long, Double: 27, 3.14, 314.16e -2
Operátory (unární) aritmetické: +, -, abs podmínkové: not
Operátory (binární) Aritmetické celočíselné: +, -, *, /, mod Aritmetické reálné: +, -, *, / Porovnávací: =,!=, <, <=, >, >= Podmínkové: andthen, and, orelse, or andthen, orelse deterministické vyhodnocování and, or nedeterministické vyhodnocení Řetězcové:, +, c in s, s[i], s[low:up] s like pattern (?, _, *, %, \) a nice string like %nice%str_ng
Množinové operace union, except, intersect Lze použít na kolece typu bag a set Operandy musí mít kompatibilní typy Pokud je jeden operand typu set a druhý typu bag, je první převeden na bag a výsledek bude také bag Porovnání: <, <=, >, >= e 1 < e 2 je true, pokud e 1 je obsažena v e 2, ale není s ní shodná e 1 <= e 2 je true, pokud e 1 je obsažena v e 2
Množinové operace Distinct Unique Odtraní duplicitní prvky z kolekce distinct(list(1, 4, 2, 3, 2, 4, 1) výsledek: list (1, 4, 2, 3) Vrací true, pokud kolekce obsahuje pouze jediný prvek
Množinové operace Element Flatten Převede kolekci obsahující pouze jediný prvek na tento prvek Pokud kolekce obsahuje více prvků vyvolá výjimku element(select x from Učitelé where x.jméno= Turing ) Převádí kolekci kolekcí typu t na kolekci typu t flatten(list(list(1, 2), list(1, 2, 3))) výsledek: list(1, 2, 1, 2, 3)
Spojení select p from Osoby p, Květiny f where p.jméno =f.jméno select p from Osoby r, p in r.potomci where r.jméno = p.jméno
Jmenné prostory import jmennýprostor.jménotřídy import jmennýprostor.jménotřídy as jiné_jménotřídy import příklad.univerzita.databáze.profesor as PProfesor select ((PProfesor)e).hodnost from Zaměstnanci e where e.id > 10000
Metody tříd Metody lze volat tam kde jejich návratový typ odpovídá očekávanému typu Metody s parametry žije_v( Paříž ) Metody bez parametrů věk() věk Metody lze používat stejně jako atributy P.nejstarší_dítě.adresa.ulice
Dotazy?