Можно создавать собственные типы данных,
включающие:
• атрибуты, каждый из которых может быть скалярной величиной или набором (мас-
сивом) других объектных/скалярных типов;
• методы для работы с данными этого типа;
• статические методы;
• необязательный метод сравнения, используемый для сортировки и сравнения
данных.
Затем этот новый тип можно использовать для создания таблиц, столбцов таблиц,
представлений или для расширения возможностей языков SQL и PL/SQL. Вновь создан-
ный пользовательский тип данных можно использовать точно так же, как и базовый тип
данных DATE.
Начнем с простого: типа данных ADDRESS_TYPE. Рассмотрим синтаксис соответ-
ствующих конструкций, их возможности, побочные эффекты, с которыми можно стол-
кнуться, и т.п. Для начала создадим простой тип:
tkyte@TKYTE816> create or replace type Address_Type
2 as object
3 (street_addrl varchar2(25),
4 street_addr2 varchar2(25),
5 city varchar2(30),
6 state varchar2(2),
7 zip_code number
8 )
9 /
Type created.
Это простейшая разновидность оператора CREATE TYPE. По ходу работы над при-
мером мы добавим в него дополнительные конструкции. Этот тип состоит только из
заданных скалярных типов, не имеет методов, специфических функций сравнения -
ничего "выдающегося". Зато его можно сразу же использовать в таблицах и в PL/SQL-
коде.
Несложный SQL-запрос позволяет получить эти данные. С помо-
щью SQL можно обращаться не только к столбцу HOME_ADDRESS, но и к каждому
из компонентов HOME_ADDRESS. Например:
tkyte@TKYTE816> select name, home_address.state, work_address.state
2 from people
3 /
select name, home_address.state, work_address.state
ERROR at line 1:
ORA-00904: invalid column nameИспользование объектно-реляционных средств
tkyte@TKYTE816> select name, P.home_address.state, P.work_address.state
2 from people P
3 /
NAME HOME_ADDRESS.STATE WORK_ADDRESS.STATE
Tom Kyte VA CA
Я продемонстрировал неправильный и правильный способ. Первый пример - это
то, что обычно пишут разработчики. Запрос, конечно, не работает. Чтобы обратиться к
компонентам объектного типа, необходимо использовать корреляционное имя, как сде-
лано во втором запросе. В нем я задал для таблицы PEOPLE псевдоним P (можно ис-
пользовать любой допустимый идентификатор, включая слово PEOPLE).
Теперь давайте немного усложним тип ADDRESS_TYPE: добавим функцию выдачи
адреса в удобном формате в виде одного поля. Для этого можно добавить в тело типа
соответствующую функцию-член:
tkyte@TKYTE816> alter type Address_Type
2 BEPLACE
3 as object
4 (street_addrl varchar2(25),
5 street_addr2 varchar2(25),
6 city varchar2(30),
7 state varchar2(2),
8 zip_code number,
9 member function toString return varchar2
10 )
11 /
Type altered.
tkyte@TKYTE816> create or replace type body Address_Type
2 as
3 member function toString return varchar2
4 is
5 begin
6 if (street_addr2 is not NULL)
7 then
8 return street_addrl || chr(10) ||
9 street_addr2 || chr(10) ||
10 city || ', ' || state || ' ' || zip_code;
11 else
12 return street_addrl || chr(10) ||
13 city || ', ' || state || ' ' || zip_code;
Type body created.
tkyte@TKYTE816> select name, p.home_address.toString()
2 from people P
3 /
Однако использование объектного типа с методами, как показано выше, дает опре-
деленные преимущества.
• Обеспечивается более совершенный механизм инкапсуляции. Тип ADDRESS_TYPE
инкапсулирует и поддерживает адрес, со всеми его атрибутами и функциональ-
ными возможностями.
• Методы более тесно привязываются к специфическим данным. Это очень важный
момент. Если используются скалярные столбцы и PL/SQL-функция, форматиру-
ющая их для вывода адреса на печать, эту функцию можно вызвать с любыми
данными. Можно передать значение столбца EMPLOYEE_NUMBER в качестве
почтового индекса, фамилию - вместо названия улицы и т.д. Привязывая метод
к атрибутам, мы гарантируем, что метод TOSTRING может работать только с
данными адреса. Пользователи, вызывающие этот метод, не должны задумывать-
ся о передаче соответствующих данных - они "уже здесь".
Однако объектный тип имеет один недостаток: в Oracle 8i он мало поддается изме-
нениям. С помощью оператора ALTER можно добавлять новые методы, но нельзя ни
удалить существующие, ни добавить дополнительные атрибуты после создания табли-
цы, использующей этот тип.
С объектными типами также связаны специфические методы MAP и ORDER. Они
используются при сортировке, сравнении или группировке экземпляров объектных ти-
пов.
Метод MAP - это функция, работающая с одним экземпляром объекта и возвраща-
ющая значение одного из скалярных типов, которое сервер Oracle будет использовать
для сравнения с другими однотипными объектами. Например, если объектный тип пред-
ставляет точку на плоскости с координатами X и Y, функция MAP может возвращать
квадратный корень из (X*X+Y*Y) - расстояние от начала координат.
Метод ORDER
принимает два экземпляра объекта - SELF и объект для сравнения с SELF. Метод
ORDER возвращает 1, если SELF больше этого объекта, -1, если SELF меньше другого
объекта или 0, если объекты равны.
Метод MAP предпочтительнее, поскольку работает
намного быстрее и даже может вызываться в параллельных запросах (метод ORDER
нельзя использовать при распараллеливании). Метод MAP достаточно вызвать для эк-
земпляра объекта один раз, и после этого сервер Oracle может использовать это значе-
ние при сортировке. Метод ORDER при сортировке большого множества, возможно,
придется вызывать сотни или тысячи раз с одними и теми же данными.
Массив VARRAY (или вложенная таблица) используется для хранения массива дан-
ных, связанных с одной строкой. Например, если необходимо хранить в таблице
PEOPLE дополнительные таблицы (скажем, массив прежних адресов проживания, на-
чиная с самого старого), можно сделать следующее:
tkyte@TKYTE816> create or replace type Address_Array_Type
2 as varray(25) of Address_Type {25 элементов типа Address_Type}
3 /
tkyte@TKYTE816> alter table people add previous_addresses
Address_Array_Type
2 /
Если объем
данных в массиве VARRAY не превышает примерно 4000 байтов, данные хранятся вме-
сте со строкой (inline). Если же объем данных больше, массив VARRAY выносится из
строки в сегмент большого объекта (как и любой большой объект).
Массивы VARRAY либо хранятся в строке как столбец типа RAW, либо (при доста-
точно большом объеме) как большой объект. Дополнительных ресурсов для поддержки
данных типа VARRAY (по сравнению с вложенной таблицей) надо очень мало, что де-
лает массив VARRAY привлекательным методом хранения повторяющихся данных. По-
иск по массиву VARRAY можно реализовать, преобразовав его данные в таблицу, что
сделает его не менее гибким, чем вложенные таблицы.