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