Опубликован: 28.12.2011 | Доступ: свободный | Студентов: 7487 / 958 | Оценка: 3.81 / 3.53 | Длительность: 19:30:00
ISBN: 978-5-9963-0488-2
Лекция 11:

Объектные типы данных в Oracle

< Лекция 10 || Лекция 11: 1234 || Лекция 12 >
Аннотация: Рассматривается самостоятельное создание и использование объектных данных в Oracle. Приводятся примеры встроенных объектных данных, полезных прикладному программисту.

Объектные типы данных в Oracle

Помимо сравнительно простых встроенных типов данных — как перешедших из стандартов SQL, так и собственных, — в Oracle имеется возможность использовать составные. Это конструируемые типы объектов, рассчитанные на хранение в БД данных, имеющих внутреннюю структуру. Эта структура известна СУБД, и СУБД позволяет с ней работать. Объектные типы позволяют хранить и обрабатывать средствами СУБД "сложно устроенные данные" более продвинутым образом, нежели это позволяет техника "больших неструктурированных объектов" типов LOB. Ввиду наличия вполне определенного типа (даже если это тип коллекции), единичное объектное значение можно полагать за скаляр, хотя оно и не будет атомарным.

Хранение в столбцах таблицы значений в виде объектов, в смысле объектного подхода (ОП в программировании и моделировании), фирма Oracle впервые обеспечила в рамках так называемой "объектно-реляционной модели" начиная с версии Oracle 8. Некоторые существенные пробелы первой реализации (например, отсутствие наследования типов) были устранены в версии 9. Примеры ниже не выходят за рамки возможностей версии 9.2, позже которой, впрочем, никаких существенных нововведений по объектной части не наблюдалось. Объектные возможности Oracle в общем следуют определениям SQL:1999, однако делают это непунктуально.

Программируемые типы данных и объекты в БД

Простой пример

Ниже приводится простой пример использования программируемых (объектных) типов.

Вначале требуется создать "тип", как разновидности хранимых элементов БД. Пример создания типа объекта (в SQL*Plus):

CREATE TYPE address_type AS OBJECT (
  zip       CHAR     ( 6 )
, location  VARCHAR2 ( 200 )
) 
/

Здесь типу ADDRESS_TYPE приписаны два "свойства" (по объектной терминологии): ZIP и LOCATION. В реальной жизни для представления адреса в типе наверняка будет указано большее количество свойств, однако в ознакомительном примере их более пространный перечень излишен и не добавит понимания техники.

Определение типа напоминает определение таблицы, однако в отличие от таблицы (а также стандарта SQL и от реляционного подхода) тип объекта в Oracle не имеет права содержать ограничений целостности (которые в таком случае можно было бы назвать "ограничениями целостности типа"). Если необходимо их указать, сделать это придется только по месту употребления типа, то есть в описании таблицы.

В соответствии с традициями объектного подхода (уместно вспомнить, что "объектной теории", в отличие от реляционной, не создано) Oracle разрешает использовать тип для создания "буквальных значений" и собственно объектов. Далее приводится сначала несколько примеров первого, а затем второго.

"Буквальные значения" фактически позволяют работать со значениями, обладающими известной СУБД структурой и однозначно определяются набором значений элементов своей структуры.

Примеры использования типа ADDRESS_TYPE для определения столбца в обычной таблице:

CREATE TABLE odept1 (
  dname    VARCHAR2 ( 20 )
, deptno   NUMBER   (  2 )  CONSTRAINT pk_odept1 PRIMARY KEY
, addr     address_type
);
CREATE TABLE oemp1 (
  ename   VARCHAR2 ( 20 )
, empno   NUMBER   (  4 )  CONSTRAINT pk_oemp1 PRIMARY KEY
, deptno  NUMBER   (  2 )  CONSTRAINT fk_oemp1 REFERENCES dept
, home    address_type
);

Столбцы ADDR и HOME можно с некоторой вольностью назвать "объектными атрибутами". Они не позволяют хранить объектные значения в виде самостоятельной сущности и ссылаться на них ссылками. Локализовать такие значения можно только по обычным правилам поиска данных в таблице.

В выражениях явно указанные объектные значения формулируются с помощью конструктора. В отличие от других объектных систем, например, от Java, в Oracle конструктор умолчательно имеет список параметров, соответствующих свойствам типа. Примеры применения в операциях добавления данных:

INSERT INTO odept1
   ( deptno, dname, addr )
VALUES
   ( 10, 'RESEARCH', address_type ( '123456', 'Archangelsk' ) )
;
INSERT INTO oemp1
   ( empno, ename, deptno, home )
VALUES
   ( 1111, 'SMITH', 10, address_type ( '789012', 'Samara' ) )
; 

Oracle допускает определенные синтаксические вольности в записи выражения над объектными данными. Здесь и далее используются частные случаи возможных формулировок.

Пример применения в запросе о сотрудниках, "работающих по месту жительства", за исключением конкретно указанного адреса:

SELECT e.ename, d.dname 
FROM   oemp1 e INNER JOIN odept1 d 
       ON e.home = d.addr
WHERE  e.home <> address_type ( '345678', 'Leningrad' )
;

Пример показывает легкость формулирования сравнения составных величин, каковыми являются адреса. Сравнение осуществляется поэлементно, путем сравнением всех свойств по очереди. Увы, но простота формулировки не дает права программисту расслабляться и забывать об особых случаях сравнения с данными типа CHAR и с NULL. Так, присутствие NULL в буквальных объектных значениях запутывает проблему сравнения еще больше, чем для случая простых типов. Сравните:

SQL> SELECT 'OK' ok FROM dual
  2  WHERE  address_type ( NULL, 'x' ) IS NOT NULL;
OK
--
OK
SQL> SELECT 'OK' ok FROM dual
  2  WHERE  address_type ( NULL, 'x' ) = address_type ( NULL, 'x' );
no rows selected

То есть получается, что x = x не дает TRUE, но притом x IS NOT NULL дает TRUE (x имеет значение).

В выражениях можно обращаться к буквальному объектному значению как к целому, а можно и к его отдельным свойствам. Во втором случае, как правило, требуется прибегать к псевдониму:

COLUMN home FORMAT A35
SELECT e.ename, e.home, e.home.zip FROM oemp1 e
;
Таблицы объектов

Созданный в БД тип можно употребить и для создания "таблиц объектов":

CREATE TABLE addresses1 OF address_type;
CREATE TABLE addresses2 OF address_type;

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

Запись занесения "строк" в такую таблицу может быть, в частности, такой:

INSERT INTO addresses1 VALUES ( '123456', 'Archangelsk' );

Пример запроса:

SELECT a.*, UPPER ( location ) FROM addresses1 a;

Объекты в таких таблицах хранятся как самостоятельные сущности, у которых имеется автоматически порождаемый СУБД внутренний уникальный идентификатор object ID, в соответствии с классическим объектным подходом позволяющий ссылаться на конкретные объекты из других таблиц или из программы. Сравнение элементов-"строк" в таблице объектов друг с другом происходит уже не по значениям свойств, как в случае объектного столбца в обычной таблице, а по значению object ID. Перейти на сравнение значений свойств позволяет функция VALUE, например:

SELECT dname FROM odept1 d, addresses1 a WHERE d.addr = VALUE ( a );

Сделан запрос об отделах, расположенных по адресам из таблицы ADDRESS1.

Не исключено, что создатели функции VALUE обсуждали другое ее название — LITERAL_VALUE. По крайней мере, оно точнее описывает совершаемое действие: создание значения со структурой из объекта. Буквальные значения сравниваются друг с другом по значениям их свойств, а объекты — по значениям object ID.

< Лекция 10 || Лекция 11: 1234 || Лекция 12 >
Ярослав Прозоров
Ярослав Прозоров

В лекции № 7 "Введение в Oracle SQL" в подразделе "Несамостоятельность группировки с обобщениями ROLLUP, CUBE и GROUPING SETS"  представленная таблица сравнения содержит ошибки - окончания запросов пропущены. Видимо, ошибки вызваны некорректным переносом материала лекции.

Володимир Миколайчук
Володимир Миколайчук
Помогите разобраться поетапно с логикой запроса
-------TOOLS
NAME PRICE TYPE
drill 155 A
sawzall 192 N
mitre saw 292 M
router 86 I
RAD 145 M
jigsaw 128 I
screwdriver 77 P
------TOOL_TYPES
TYPE USAGE
A Always
I Often
M Sometimes
N Rarely
P Never

Запрос SQL:
SELECT t.type, SUM(t.price)
FROM tools t
GROUP BY t.type
HAVING SUM(t.price) >= (SELECT AVG(price)
FROM tools
WHERE type IN (SELECT type
FROM tool_types
WHERE usage = 'Often'));

И сколько строк он все таки вернет