ПБД (9) - Лекция №8 - OQL

Материал из Кафедра ИУ5 МГТУ им. Н.Э.Баумана - студенческое сообщество
Перейти к: навигация, поиск
Этот конспект ещё не дописан.
Здесь не хватает:
   - примеров запросов на языке OQL.


SQL

Пользовательские типы данных

User Defined Types - UDT.

Создаём свой тип:

CREATE TYPE Addr AS
(
    city CHAR(20),
    street VARCHAR(100)
)
-- объявление метода
method fullad() RETURNS VARCHAR(130);
 
-- определение метода
CREATE method fullad() RETURNS VARCHAR(130)
FOR Addr
BEGIN
    RETURN SELF.city || SELF.street
END;

Используем его при описании других:

CREATE TYPE Studia AS
(
    sname VARCHAR(50),
    addr Addr
);
 
CREATE TYPE Actor AS
(
    inn INT,
    fio VARCHAR(50),
    addr Addr
);

Создаём таблицы со ссылками:

CREATE TABLE Tact OF Actor
(
    PRIMARY KEY (inn),
    REF IS Ida system generated
);
 
CREATE TABLE TSt
(
    REF IS Ids system generated
)

Создаём тип со ссылками:

CREATE TYPE Film AS
(
    title VARCHAR(80),
    YEAR unt,
    len INT,
    TYPE CHAR(2),
    st REF(Studia) [SCOPE TSt] -- SCOPE показывает, что это на конкретную талицу
);

Ещё таблицы:

CREATE TABLE FA
(
    act REF(Actor) SCOPE TAct,
    film REF(Film) SCOPE TF
);
 
CREATE TABLE TF OF Film
(
    REF IS Idf system generated
);

Запросы к UDT

-- один ко многим
SELECT YEAR, len st->sname, st->addr.city, st->addr.fullad()
FROM TF
WHERE title = 'The Matrix'
 
-- многие ко многим (обращение к одной таблице, которая её реализует)
SELECT film->title, film->YEAR, film->st->name
FROM FA
WHERE act->fio='Иванов'
 
-- разыменование ссылок
SELECT deref(act)
FROM FA
WHERE film->title='The Matrix' -- выведет всех актёров этого фильма

Методы

Создаются системой автоматически.

Методы обозреватели

Они же getter. Совпадают с названием поля, не имеют параметров. Нужны для получения значений полей.

SELECT f.title(), f.len()
FROM TF
WHERE f.type='BW'
Методы модификаторы

Они же setter. Для изменения значения полей.

Методы генераторы

Они же конструкторы.

DECLARE newA Addr;
DECLARE newS Stud;
 
SET newA = Addr();   -- вызов конструктора
newA.city('Москва');
newA.street('Ленина, 2');
 
SET newS = Studia(); -- вызов конструктора
newS.sname('Мосфильм');
news.addr(newA);
 
INSERT INTO TSt VALUES(newS);

Сравнение типов

CREATE ORDERING FOR Addr
<EQUALS ONLY | ORDER FULL | RELATIVE WITH f> BY STATE
-- f - это функция, выполняющая сравнение двух параметров
-- она не стандартная, её надо создать
CREATE FUNCTION f(x1 Addr, x2 Addr) RETURNS INT
    IF x1.city > x2.city TNEN RETURN 1;
    ELSE IF x1.city < x2.city TNEN RETURN -1;
    ELSE IF x1.street > x2.street TNEN RETURN 1;
    ELSE IF x1.street < x2.street TNEN RETURN -1;
    ELSE RETURN 0;
    END IF;

Производные типы

CREATE TYPE имя UNDER базовый тип AS
(
    поле тип,
    ...
    [[NOT] instantiable] -- можно ли на его основе создать ещё тип
    [NOT] final          -- можно ли его переопределять
    <REF IS system generated | REF USING тип | REF USING (атрибут)>
);
 
[overriding]
[<instance | static | constructor>]
method название(параметры) RETURNS тип
[SELF AS <RESULT | locator>]
[parameter STYLE <SQL | Java | ...>]
[[NOT] deteministic]
[no SQL | contains SQL | ...]
[RETURN <NULL ON NULL INPUT | called ON NULL input>]

OQL

Object Query Language.

class Film(extent EF)
{
    attribute string title;
    attribute string year;
    attribute string len;
    attribute string type;
 
    relationship Stud st inverse Stud::fl;
    relationship set <Actor> acts inverse Actor::films;
 
    set <Stud> StofFl();
 
    -- метод
    int firstFilm();
}
 
class Actor(extent EA)
{
    attribute string fio;
    attribute int inn;
 
    relationship set <Film> films inverse ... ;
 
    -- атрибут-структура
    attribute Struct{string city, string street} addr;
}

Запросы на OQL

Связь М-М, все актеры, которые снимались в фильме:

SELECT a.fio
FROM EF f, f.acts a
WHERE f.title="Иванов" AND f.year < 1950
SELECT a.fio, a.addr
FROM EA a
WHERE for all f in a.films : f.st.sname="Мосфильм"

Коллекция - элемент, множество связанных объектов и вложенный подзапрос. Пример с группировкой:

4 SELECT st, y , sumlen: sum(SELECT P.f.len FROM PARTITION P)
1 FROM ES st, st.fms F
2 WHERE f.year>2000
3 GROUP BY st:st.name, y:f.year

PARTITION - результат группировки, коллекция всех объектов, которые попали в отдельную группу. Здесь st и f. WHERE работает до группировки. HAVING накладывает ограничения на группы. Если он есть, то выполняется 4-ым шагом ( до SELECT'а).

HAVING MIN(SELECT p.f.len FROM PARTITION P)>60.

Сортировка:

ORDER BY ASC st, year

Агрегаты

COUNT() - Для любых
MIN() - для подлежащих сортировке
SUM() - только для числовых
AVG() - только для числовых
MAX() - для подлежащих сортировке

Можно применять к коллекции:

COUNT(EF) - кол-во элементов в экстенте.


Поддерживаются кванторы:

SELECT a
FROM EA a
WHERE FOR ALL F IN a.films:F.st.name="ЛенФильм" AND f.year=2016
FOR ALL IN - квантор всеобщности
SELECT a
FROM EA a
WHERE EXISTS f1 IN a.films:f.yaer<2000

Запрос на единственность:

SELECT s
FROM ES s
WHERE COUNT(s.fms)=1
Те студии, которые сняли только один фильм.

По умолчанию возвращается мультимножество структур.

SELECT a.fio, f.year
Bag<struct{struct{f, i, o}, integer year}>

Если хочется SET:

SELECT DISTINCT

Если хочется LIST:

ORDER BY

Можно и свою коллекцию:

SELECT struct(fam:a.fio.f, yearMade:f.year)
Если поле одно, то структура не формируется.


(SELECT a
FROM EA a, a.films f
WHERE f.stud.name="МосФильм")
EXCEPT
(SELECT a
FROM EA a, EF f
WHERE f.stud.name="Экран")
 
Аналогично можно с UNION и INTERSECT