Создание объекта в oracle
Аннотация: Рассматривается самостоятельное создание и использование объектных данных в Oracle. Приводятся примеры встроенных объектных данных, полезных прикладному программисту.
Using PL/SQL Collections with SQL Object Types
Collections let you manipulate complex datatypes within PL/SQL. Your program can compute subscripts to process specific elements in memory, and use SQL to store the results in database tables.
In SQL*Plus, you can create SQL object types whose definitions correspond to PL/SQL nested tables and varrays, as shown in Example 12-15. Each item in column dept_names is a nested table that will store the department names for a specific region. The NESTED TABLE clause is required whenever a database table has a nested table column. The clause identifies the nested table and names a system-generated store table, in which Oracle stores the nested table data.
Within PL/SQL, you can manipulate the nested table by looping through its elements, using methods such as TRIM or EXTEND , and updating some or all of the elements. Afterwards, you can store the updated table in the database again. You can insert table rows containing nested tables, update rows to replace its nested table, and select nested tables into PL/SQL variables. You cannot update or delete individual nested table elements directly with SQL; you have to select the nested table from the table, change it in PL/SQL, then update the table to include the new nested table.
Example 12-15 Using INSERT, UPDATE, DELETE, and SELECT Statements With Nested Tables
Example 12-16 shows how you can manipulate SQL varray object types with PL/SQL statements. In this example, varrays are transferred between PL/SQL variables and SQL tables. You can insert table rows containing varrays, update a row to replace its varray, and select varrays into PL/SQL variables. You cannot update or delete individual varray elements directly with SQL; you have to select the varray from the table, change it in PL/SQL, then update the table to include the new varray.
Example 12-16 Using INSERT, UPDATE, DELETE, and SELECT Statements With Varrays
In Example 12-17, PL/SQL BULK COLLECT is used with a multilevel collection that includes an object type.
Example 12-17 Using BULK COLLECT with Nested Tables
Manipulating Objects Through Ref Modifiers
You can retrieve refs using the function REF , which takes as its argument a correlation variable.
Example 12-8 Updating Rows in an Object Table With a REF Modifier
DECLARE emp employee_typ; emp_ref REF employee_typ; BEGIN SELECT REF(e) INTO emp_ref FROM employee_tab e WHERE e.employee_id = 370; UPDATE employee_tab e SET e.address = address_typ('8701 College', 'Oakland', 'CA', '94321') WHERE REF(e) = emp_ref; END; /
You can declare refs as variables, parameters, fields, or attributes. You can use refs as input or output variables in SQL data manipulation statements.
You cannot navigate through refs in PLSQL. For example, the assignment in Example 12-9 using a ref is not allowed. Instead, use the function DEREF or make calls to the package UTL_REF to access the object. For information on the REF function, see Oracle Database SQL Reference .
Example 12-9 Using DEREF in a SELECT INTO Statement
For information on the DEREF function, see Oracle Database SQL Reference .
Calling Object Constructors and Methods
Calls to a constructor are allowed wherever function calls are allowed. Like all functions, a constructor is called as part of an expression, as shown in Example 12-4 and Example 12-5.
Example 12-5 Inserting Rows in an Object Table
When you pass parameters to a constructor, the call assigns initial values to the attributes of the object being instantiated. When you call the default constructor to fill in all attribute values, you must supply a parameter for every attribute; unlike constants and variables, attributes cannot have default values. You can call a constructor using named notation instead of positional notation.
Like packaged subprograms, methods are called using dot notation. In Example 12-6, the display_address method is called to display attributes of an object. Note the use of the VALUE function which returns the value of an object. VALUE takes as its argument a correlation variable. In this context, a correlation variable is a row variable or table alias associated with a row in an object table.
Example 12-6 Accessing Object Methods
In SQL statements, calls to a parameterless method require an empty parameter list. In procedural statements, an empty parameter list is optional unless you chain calls, in which case it is required for all but the last call. You cannot chain additional method calls to the right of a procedure call because a procedure is called as a statement, not as part of an expression. Also, if you chain two function calls, the first function must return an object that can be passed to the second function.
For static methods, calls use the notation type_name . method_name rather than specifying an instance of the type.
When you call a method using an instance of a subtype, the actual method that is executed depends on the exact declarations in the type hierarchy. If the subtype overrides the method that it inherits from its supertype, the call uses the subtype's implementation. Or, if the subtype does not override the method, the call uses the supertype's implementation. This capability is known as dynamic method dispatch.
Резюме
В этой главе мы увидели тип объекта и его свойства. Мы также обсудили конструкторы, члены, атрибуты, наследование и равенство в объектах PL / SQL.
Accessing Object Attributes With Dot Notation
You refer to an attribute by name. To access or change the value of an attribute, you use dot notation. Attribute names can be chained, which lets you access the attributes of a nested object type. For example:
Example 12-4 Accessing Object Attributes
Создать объект в Oracle
Тип объекта не может быть создан на уровне подпрограммы, они могут быть созданы только на уровне схемы. После того, как тип объекта определен в схеме, его можно использовать в подпрограммах. Тип объекта может быть создан с помощью «CREATE TYPE». Тело типа может быть создано только после создания его типа объекта.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает создание ‘OBJECT’ с атрибутами и ‘OBJECT-BODY’ с методами.
- Методы также могут быть перегружены в теле объекта.
Manipulating Individual Collection Elements with SQL
By default, SQL operations store and retrieve whole collections rather than individual elements. To manipulate the individual elements of a collection with SQL, use the TABLE operator. The TABLE operator uses a subquery to extract the varray or nested table, so that the INSERT , UPDATE , or DELETE statement applies to the nested table rather than the top-level table.
To perform DML operations on a PL/SQL nested table, use the operators TABLE and CAST . This way, you can do set operations on nested tables using SQL notation, without actually storing the nested tables in the database.
The operands of CAST are PL/SQL collection variable and a SQL collection type (created by the CREATE TYPE statement). CAST converts the PL/SQL collection to the SQL type.
Example 12-14 Performing Operations on PL/SQL Nested Tables With CAST
Равенство объектов PL / SQL
Экземпляр объекта, принадлежащий тем же объектам, можно сравнить на равенство. Для этого нам нужен специальный метод в типе объекта, который называется «ORDER».
Этот метод ORDER должен быть функцией, которая возвращает числовой тип. Он принимает два параметра в качестве входных данных (первый параметр: идентификатор экземпляра самообъекта, второй параметр: идентификатор другого экземпляра объекта).
Идентификатор экземпляра двух объектов сравнивается, и результат возвращается в числовом виде.
- Положительное значение означает, что экземпляр объекта SELF больше, чем другой экземпляр.
- Отрицательное значение означает, что экземпляр объекта SELF меньше другого экземпляра.
- Ноль означает, что экземпляр объекта SELF равен другому экземпляру.
- Если какой-либо из экземпляров имеет значение null, эта функция вернет значение null.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает функцию ORDER, которую необходимо включить в тело типа для проверки на равенство.
- Параметр для этой функции должен быть экземпляром объекта того же типа.
- Вышеупомянутая функция может быть вызвана как «obj_instance_1.match (obj_instance_2)», и это выражение вернет числовое значение, как показано, где obj_instance_1 и obj_instance_2 являются экземпляром object_type_name.
Пример 1 : В следующем примере мы увидим, как сравнивать два объекта. Мы собираемся создать два экземпляра и сравнить между ними атрибут «зарплата». Мы собираемся сделать два шага.
- Шаг 1: Создание типа объекта и тела.
- Шаг 2: Создание анонимного блока для вызова сравнить экземпляр объекта.
Шаг 1) Создание типа объекта и тела.
Объяснение кода:
- Строка кода 1-4: создание типа объекта emp_object_equality с 1 атрибутом и 1 элементом.
- Строка кода 6-16 : определение функции ORDER, которая сравнивает атрибут salary экземпляра SELF и типа экземпляра параметра. Возвращает отрицательный результат, если зарплата SELF меньше, или положительная, если зарплата SELF больше, и 0, если зарплата равна.
Вывод кода:
Шаг 2) Создание анонимного блока для вызова сравнить экземпляр объекта.
Вывод
Объяснение кода:
Конструкторы
Конструкторы – это неявный метод объекта, на который можно ссылаться с тем же именем, что и у типа объекта. Всякий раз, когда объект упоминается впервые, этот конструктор будет вызываться неявно.
Мы также можем инициализировать объекты с помощью этого конструктора. Конструктор может быть определен явно путем определения члена в теле типа объекта с тем же именем типа объекта.
Пример 1 : В следующем примере мы собираемся использовать элемент типа объекта для вставки записи в таблицу emp со значениями (‘RRR’, 1005, 20000, 1000) и (‘PPP’, 1006, 20000, 1001). После того, как данные вставлены, мы собираемся отобразить то же самое, используя элемент типа объекта. Мы также собираемся использовать явный конструктор для заполнения идентификатора менеджера по умолчанию значением 1001 для второй записи.
Мы собираемся выполнить это в следующих шагах.
- Шаг 1:
- Создать тип объекта
- Тип объекта тело
Шаг 1) Создать тип объекта и тело типа объекта
Код Объяснение
- Строка кода 1-9 : создание типа объекта emp_object с 4 атрибутами и 3 членами. Он содержит определение конструкторов только с 3 параметрами. (Фактический неявный конструктор будет содержать количество параметров, равное количеству атрибутов, присутствующих в типе объекта)
- Строка кода 10 : создание тела типа.
- Строка кода 11-21 : определение явного конструктора. Присвоение значения параметра атрибутам и присвоение значения атрибуту «manager» со значением по умолчанию «1001».
- Строка кода 22-26 : определение элемента ‘insert_records’, в котором значения атрибутов вставляются в таблицу ’emp’.
- Строка кода 27-34 : определение элемента ‘display_records’, в котором отображаются значения атрибутов типа объекта.
Вывод
Тип тела создан
Шаг 2) Создание анонимного блока для вызова созданного типа объекта через неявный конструктор для emp_no 1005
Код Объяснение
- Строка кода 37-45 : вставка записей с использованием неявного конструктора. Призыв к конструктору содержит фактическое количество значений атрибутов.
- Строка кода 38 : объявляет guru_emp_det как тип объекта emp_object.
- Строка кода 41 : оператор ‘guru_emp_det.display_records’ вызвал функцию-член diplay_records, и отображаются значения атрибутов
- Строка кода 42 : оператор «guru_emp_det.insert_records» вызвал функцию-член «insert_records», и значения атрибутов вставлены в таблицу.
Вывод
Имя сотрудника: RRR
Номер сотрудника: 1005
Шаг 3) Создание анонимного блока для вызова созданного типа объекта через явный конструктор для emp_no 1006
Вывод
Объяснение кода:
- Строка кода 46-53 : вставка записей с использованием явного конструктора.
- Строка кода 46 : объявляет guru_emp_det как тип объекта emp_object.
- Строка кода 50 : оператор ‘guru_emp_det.display_records’ вызвал функцию-член ‘display_records’, и значения атрибутов отображаются
- Строка кода 51 : оператор ‘guru_emp_det.insert_records’ вызвал функцию-член ‘insert_records’, и значения атрибутов были вставлены в таблицу.
Наследование в типе объекта
Свойство наследования позволяет типу подобъекта получать доступ ко всем атрибутам и членам типа суперобъекта или типа родительского объекта.
Тип подобъекта называется типом наследуемого объекта, а тип суперобъекта называется типом родительского объекта. Синтаксис ниже показывает, как создать родительский и унаследованный тип объекта.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает создание типа SUPER.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает создание типа SUB. Он содержит все члены и атрибуты родительского типа объекта.
Пример 1: В приведенном ниже примере мы собираемся использовать свойство наследования, чтобы вставить запись с идентификатором менеджера как «1002» для следующей записи («RRR», 1007, 20000).
Мы собираемся выполнить вышеуказанную программу в следующих шагах
- Шаг 1: Создать тип SUPER.
- Шаг 2: Создайте тип SUB и тело.
- Шаг 3: Создание анонимного блока для вызова типа SUB.
Шаг 1) Создайте тип SUPER или родительский тип.
Объяснение кода:
- Строка кода 1-9 : создание типа объекта emp_object с 4 атрибутами и 3 членами. Он содержит определение конструкторов только с 3 параметрами. Он был объявлен как «НЕ ФИНАЛ», поэтому это родительский тип.
Шаг 2) Создайте тип SUB под типом SUPER.
Объяснение кода:
- Строка кода 10-13 : создание объекта sub_emp_object как унаследованного типа с дополнительным атрибутом default_manager и объявлением процедуры члена.
- Строка кода 14 : создание тела для унаследованного типа объекта.
- Строка кода 1 6 -21 : определение процедуры-члена, которая вставляет записи в таблицу «emp» со значениями из типа объекта «SUPER», за исключением значения менеджера. Для значения менеджера используется «default_manager» из типа «SUB».
Шаг 3) Создание анонимного блока для вызова типа SUB
Объяснение кода:
- Строка кода 25 : объявление ‘guru_emp_det’ как типа ‘sub_emp_object’.
- Строка кода 27 : инициализация объекта неявным конструктором. Конструктор имеет 5 параметров (4 атрибута от типа PARENT и 2 атрибута от типа SUB). Последний параметр (1002) определяет значение для атрибута default_manager
- Строка кода 28 : Вызов члена ‘insert_default_mgr’ для вставки записей с идентификатором менеджера по умолчанию, переданным в конструктор.
Участники / Методы
Члены или Методы – это подпрограммы, определенные в типе объекта. Они не используются для хранения каких-либо данных. Они в основном используются для определения процесса внутри типа объекта. Для примеров проверки данных перед заполнением типа объекта. Они объявлены в разделе типа объекта и определены в разделе тела типа объекта типа объекта. Раздел тела в типе объекта является необязательной частью. Если члены отсутствуют, тип объекта не будет содержать части тела.
Manipulating Objects in PL/SQL
This section describes how to manipulate object attributes and methods in PL/SQL.
Updating and Deleting Objects
From inside a PL/SQL block you can modify and delete rows in an object table.
Example 12-7 Updating and Deleting Rows in an Object Table
Declaring and Initializing Objects in PL/SQL
An object type can represent any real-world entity. For example, an object type can represent a student, bank account, computer screen, rational number, or data structure such as a queue, stack, or list.
Currently, you cannot define object types in a PL/SQL block, subprogram, or package. You can define them interactively in SQL*Plus using the SQL statement CREATE TYPE . See Example 1-17, "Defining an Object Type".
For information on the CREATE TYPE SQL statement, see Oracle Database SQL Reference . For information on the CREATE TYPE BODY SQL statement, see Oracle Database SQL Reference .
After an object type is defined and installed in the schema, you can use it to declare objects in any PL/SQL block, subprogram, or package. For example, you can use the object type to specify the datatype of an attribute, column, variable, bind variable, record field, table element, formal parameter, or function result. At run time, instances of the object type are created; that is, objects of that type are instantiated. Each object can hold different values.
Such objects follow the usual scope and instantiation rules. In a block or subprogram, local objects are instantiated when you enter the block or subprogram and cease to exist when you exit. In a package, objects are instantiated when you first reference the package and cease to exist when you end the database session.
Example 12-1 shows how to create an object type, object body type, and a table of object types.
Example 12-1 Working With Object Types
Объявление инициализации типа объекта
Как и другие компоненты в PL / SQL, типы объектов также должны быть объявлены перед использованием их в программе.
После создания типа объекта его можно использовать в декларативном разделе подпрограммы для объявления переменной этого типа объекта.
Всякий раз, когда любая переменная объявляется в подпрограмме как тип объекта, во время выполнения будет создан новый экземпляр типа объекта, и этот вновь созданный экземпляр может быть связан с именем переменной. Таким образом, один тип объекта может хранить несколько значений в разных экземплярах.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает объявление переменной в качестве типа объекта в декларативном разделе.
Как только переменная объявлена как тип объекта в подпрограмме, она будет атомарно нулевой, т.е. весь сам объект будет нулевым. Его необходимо инициализировать значениями, чтобы использовать их в программе. Их можно инициализировать с помощью конструкторов.
Конструкторы – это неявный метод объекта, на который можно ссылаться с тем же именем, что и у типа объекта. Приведенный ниже синтаксис показывает инициализацию типа объекта.
Синтаксис Объяснение:
- Приведенный выше синтаксис показывает инициализацию экземпляра типа объекта с нулевым значением.
- Теперь сам объект не является нулевым, так как он был инициализирован, но атрибуты внутри объекта будут нулевыми, поскольку мы не присваиваем никаких значений этим атрибутам.
Declaring Objects in a PL/SQL Block
You can use object types wherever built-in types such as CHAR or NUMBER can be used. In Example 12-2, you declare object emp of type employee_typ . Then, you call the constructor for object type employee_typ to initialize the object.
Example 12-2 Declaring Object Types in a PL/SQL Block
You can declare objects as the formal parameters of functions and procedures. That way, you can pass objects to stored subprograms and from one subprogram to another. In the next example, you use object type employee_typ to specify the datatype of a formal parameter:
PROCEDURE open_acct (new_acct IN OUT employee_typ) IS .
In the following example, you use object type employee_typ to specify the return type of a function:
FUNCTION get_acct (acct_id IN NUMBER) RETURN employee_typ IS .
Компоненты типов объектов
Тип объекта PL / SQL содержит в основном два компонента.
Объектные типы данных в Oracle
Помимо сравнительно простых встроенных типов данных — как перешедших из стандартов SQL , так и собственных, — в Oracle имеется возможность использовать составные. Это конструируемые типы объектов, рассчитанные на хранение в БД данных, имеющих внутреннюю структуру. Эта структура известна СУБД , и СУБД позволяет с ней работать. Объектные типы позволяют хранить и обрабатывать средствами СУБД "сложно устроенные данные" более продвинутым образом, нежели это позволяет техника "больших неструктурированных объектов" типов LOB . Ввиду наличия вполне определенного типа (даже если это тип коллекции ), единичное объектное значение можно полагать за скаляр, хотя оно и не будет атомарным.
Хранение в столбцах таблицы значений в виде объектов, в смысле объектного подхода (ОП в программировании и моделировании), фирма Oracle впервые обеспечила в рамках так называемой "объектно-реляционной модели" начиная с версии Oracle 8. Некоторые существенные пробелы первой реализации (например, отсутствие наследования типов ) были устранены в версии 9. Примеры ниже не выходят за рамки возможностей версии 9.2, позже которой, впрочем, никаких существенных нововведений по объектной части не наблюдалось. Объектные возможности Oracle в общем следуют определениям SQL :1999, однако делают это непунктуально.
Программируемые типы данных и объекты в БД
Простой пример
Ниже приводится простой пример использования программируемых (объектных) типов.
Вначале требуется создать "тип", как разновидности хранимых элементов БД. Пример создания типа объекта (в SQL*Plus):
Здесь типу ADDRESS_TYPE приписаны два "свойства" (по объектной терминологии): ZIP и LOCATION . В реальной жизни для представления адреса в типе наверняка будет указано большее количество свойств, однако в ознакомительном примере их более пространный перечень излишен и не добавит понимания техники.
Определение типа напоминает определение таблицы, однако в отличие от таблицы (а также стандарта SQL и от реляционного подхода) тип объекта в Oracle не имеет права содержать ограничений целостности (которые в таком случае можно было бы назвать "ограничениями целостности типа"). Если необходимо их указать, сделать это придется только по месту употребления типа, то есть в описании таблицы.
В соответствии с традициями объектного подхода (уместно вспомнить, что "объектной теории", в отличие от реляционной, не создано) Oracle разрешает использовать тип для создания "буквальных значений" и собственно объектов. Далее приводится сначала несколько примеров первого, а затем второго.
"Буквальные значения" фактически позволяют работать со значениями, обладающими известной СУБД структурой и однозначно определяются набором значений элементов своей структуры.
Примеры использования типа ADDRESS_TYPE для определения столбца в обычной таблице:
Столбцы ADDR и HOME можно с некоторой вольностью назвать "объектными атрибутами". Они не позволяют хранить объектные значения в виде самостоятельной сущности и ссылаться на них ссылками. Локализовать такие значения можно только по обычным правилам поиска данных в таблице.
В выражениях явно указанные объектные значения формулируются с помощью конструктора. В отличие от других объектных систем, например, от Java, в Oracle конструктор умолчательно имеет список параметров, соответствующих свойствам типа. Примеры применения в операциях добавления данных:
Oracle допускает определенные синтаксические вольности в записи выражения над объектными данными. Здесь и далее используются частные случаи возможных формулировок.
Пример применения в запросе о сотрудниках, "работающих по месту жительства", за исключением конкретно указанного адреса:
Пример показывает легкость формулирования сравнения составных величин, каковыми являются адреса. Сравнение осуществляется поэлементно, путем сравнением всех свойств по очереди. Увы, но простота формулировки не дает права программисту расслабляться и забывать об особых случаях сравнения с данными типа CHAR и с NULL . Так, присутствие NULL в буквальных объектных значениях запутывает проблему сравнения еще больше, чем для случая простых типов. Сравните:
То есть получается, что x = x не дает TRUE , но притом x IS NOT NULL дает TRUE ( x имеет значение).
В выражениях можно обращаться к буквальному объектному значению как к целому, а можно и к его отдельным свойствам. Во втором случае, как правило, требуется прибегать к псевдониму:
Таблицы объектов
Созданный в БД тип можно употребить и для создания "таблиц объектов":
Хотя для этой категории хранимых элементов используется термин "таблица", такая таблица всегда содержит ровно один столбец, и именно объектного типа.
Запись занесения "строк" в такую таблицу может быть, в частности, такой:
SELECT a.*, UPPER ( location ) FROM addresses1 a;
Объекты в таких таблицах хранятся как самостоятельные сущности, у которых имеется автоматически порождаемый СУБД внутренний уникальный идентификатор object ID, в соответствии с классическим объектным подходом позволяющий ссылаться на конкретные объекты из других таблиц или из программы. Сравнение элементов-"строк" в таблице объектов друг с другом происходит уже не по значениям свойств, как в случае объектного столбца в обычной таблице, а по значению object ID. Перейти на сравнение значений свойств позволяет функция VALUE, например:
Сделан запрос об отделах, расположенных по адресам из таблицы ADDRESS1 .
Не исключено, что создатели функции VALUE обсуждали другое ее название — LITERAL_VALUE . По крайней мере, оно точнее описывает совершаемое действие: создание значения со структурой из объекта. Буквальные значения сравниваются друг с другом по значениям их свойств, а объекты — по значениям object ID.
В версии 8 в Oracle появилась возможность хранения неатомарных (нескалярных) значений в поле таблицы, а именно объекта в смысле объектного подхода (в рамках так называемой “объектно-реляционной модели” Oracle). Некоторые существенные пробелы этой первой реализации были устранены в версии 9. Примеры ниже используют возможности версии 9.2.
Сразу надо предостеречь от преувеличений достоинств объектного подхода в базах данных вообще. Действительно, неискушенный читатель некоторых руководств или рекламных материалов быстро впадет в недоумение: зачем же такие маститые разработчики СУБД, как фирмы IBM, Informix или Oracle так долго занимались табличной организацией данных, когда все это время рядом существовала более совершенная, удобная и т. д. объектная, первая реализация которой фирмой Xerox известна с 1980 года?
Непредвзятый ответ состоит в том, что ни табличная организация (часто вольно называемая “реляционной” применительно к конкретным СУБД), ни объектная не являются универсально “хорошими”, и что имеются свои достоинства и недостатки у одной и у другой. Некоторые соображения относительно областей применения обоих подходов к хранению данных можно найти в статье “Что объектам здорово, то реляциям смерть, и наоборот, и еще пол-оборота”.
В целом объектная реализация в Oracle традиционна для объектного подхода вообще. В основе лежит понятие объекта как совокупности свойств (атрибутов), причем действия с объектом регламентируются формулируемым набором методов (процедур или функций). Тип объекта задается сохраняемым в БД объектом TYPE.
Хранимые объекты
Простой пример
Рассмотрим схему БД, где хранятся данные о сотрудниках и отделах. Будем работать в схеме SCOTT, из которой на время нужно удалить таблицы EMP и DEPT (позже мы их восстановим).
Предположим, что и те, и другие имеют адреса: сотрудники - домашний, а отделы – юридический. Адрес имеет несколько полей (например, “индекс”, “район”, “населенный пункт”, “место”). В традиционной табличной реализации есть два способа промоделировать наличие адреса:
- включить одинаковые группы полей в таблицы сотрудников и отделов;
- создать отдельную таблицу адресов и включить в таблицы сотрудников и отделов ссылки на нее.Первое решение неудобно тем, что адрес теряет свою идентичность: неудобно, например, сравнивать адреса, особенно в разных таблицах. Второе решение искусственно, если только не считать адреса самостоятельными объектами моделирования.
Объектные возможности последних версий Oracle дают возможность более приемлемой альтернативы. Для описания адреса создадим тип (здесь и далее предполагается использование в качестве рабочего инструмента SQL*Plus):
CREATE TYPE address_typ AS OBJECT (
zip CHAR(6),
location VARCHAR2(200))
/Воспользуемся этим типом для описания сотрудников и отделов:
CREATE TABLE dept (
dname VARCHAR2(50),
deptno NUMBER CONSTRAINT pk_dept PRIMARY KEY,
addr address_typ);CREATE TABLE emp (
ename VARCHAR2(50),
empno NUMBER CONSTRAINT pk_emp PRIMARY KEY,
deptno NUMBER CONSTRAINT fk_emp REFERENCES dept,
home address_typ);Проверим описания созданных объектов:
DESCRIBE address_typ
DESCRIBE dept
DESCRIBE empПример заведения сотрудников и отделов:
INSERT INTO dept VALUES (
'Sales',
10,
address_typ('123456', 'Boston 123. '));INSERT INTO emp VALUES (
'Smith',
1001,
10,
address_typ('123333', 'Boston 567. '));Здесь выражение ADDRESS_TYP('123333', 'Boston 567. ') означает обращение к конструктору объекта, то есть к функции, автоматически создаваемой СУБД при заведении нового типа для возможности создавать новые объекты этого типа с нужными значениями атрибутов. Понятие конструктора общепринято в объектном подходе. В приведенных предложениях INSERT простановку адреса можно оформить чуть иначе, добавив, в соответствии с духом объектного подхода, ключевое слово NEW перед обращением к конструктору:
INSERT INTO emp VALUES (
'Allen',
1002,
10,
NEW address_typ('123456', 'Boston 123. '));COLUMN dname FORMAT A20
COLUMN ename FORMAT A20
COLUMN addr FORMAT A40
COLUMN home FORMAT A40SELECT * FROM dept;
SELECT * FROM emp;
SELECT ename, home FROM emp;
SELECT e.ename, d.dname FROM emp e, dept d WHERE e.home = d.addr;
SELECT e.ename, e.home.zip FROM emp e;
UPDATE emp
SET home = address_typ('123457', 'Boston 777. ')
WHERE ename = 'Allen';UPDATE emp e SET e.home.zip = '123458' WHERE ename = 'Allen';
Создание таблицы объектов
Если адрес интересует нас как самостоятельная сущность, а не атрибут прочих сущностей, созданный для адреса тип можно использовать для создания таблиц объектов:
CREATE TABLE addr_list1 OF address_typ;
CREATE TABLE addr_list2 OF address_typ;
Таблицы объектов в Oracle было бы точнее называть списками объектов, так как это всегда таблицы ровно из одного столбца объектного типа.
Заполнение данными происходит как и ранее:
INSERT INTO addr_list1 VALUES
(NEW address_typ('123456', 'Boston 123. '));INSERT INTO addr_list1 VALUES
(address_typ('123458', 'Boston 123. '));INSERT INTO addr_list2 VALUES
(address_typ('123333', 'Boston 567. '));COLUMN location FORMAT A30
SELECT * FROM addr_list1;
SELECT VALUE(a) FROM addr_list1 a;
SELECT e.ename, e.home
FROM addr_list1 a, emp e
WHERE VALUE(a) = e.home;(Функция VALUE специально придумана для возвращения значений объектов, а не атрибутов объектов по отдельности).
Ссылки на объект
Объекты, заведенные в объектных таблицах, имеют одно преимущество перед объектами, указанными как атрибут строки: на них можно ссылаться. Ссылка есть уникальный внутренний идентификатор объекта, и получить его можно с помощью функции REF:
COLUMN ref FORMAT A90
COLUMN value FORMAT A40SELECT REF(a) ref, VALUE(a) FROM addr_list1 a;
Теперь можно поменять описание таблицы, например, DEPT, чтобы она заимствовала адреса отделов из имеющегося списка, а не хранила вместе со своими данными:
ALTER TABLE dept DROP (addr);
ALTER TABLE dept ADD (addr REF address_typ SCOPE IS addr_list1);
SELECT * FROM dept;
UPDATE dept d
SET d.addr =
(SELECT REF(a)
FROM addr_list1 a
WHERE VALUE(a)= address_typ('123458', 'Boston 123. '))
WHERE d.deptno = 10;SELECT * FROM dept;
Фраза SCOPE IS при определении типа как ссылки на существующий объект необязательна, но позволяет фактически ссылаться только на объекты какой-нибудь объектной таблицы.
Раскрытие ссылки делается с помощью специальной функции DEREF:
COLUMN deref(addr) FORMAT A40
SELECT d.dname, DEREF(addr) FROM dept d;
Однако при обращении к нижележащим атрибутам раскрытие может выполняться и неявно (неявное преобразование типов, присутствующее в Oracle-диалекте SQL):
SELECT d.dname, d.addr.zip FROM dept d;
вместо более правильного
SELECT d.dname, DEREF(d.addr).zip FROM dept d;
Методы объектов
Выше было рассмотрено определение типа, содержащее описание атрибутов (“свойств”). Создадим тип сотрудников, в котором определен еще и метод:
CREATE TYPE employee_typ AS OBJECT (
ename VARCHAR2(50),
hiredate DATE,
deptno NUMBER,
home REF address_typ,
MEMBER FUNCTION days_at_company RETURN NUMBER)
/Для описания тела метода-функции необходимо создать тело типа (аналогия пакет – тело пакета в PL/SQL):
CREATE TYPE BODY employee_typ IS
MEMBER FUNCTION days_at_company RETURN NUMBER IS
BEGIN
RETURN TRUNC(SYSDATE-hiredate);
END;
END;
/Создадим таблицу объектов-сотрудников:
CREATE TABLE emp OF employee_typ;
INSERT INTO emp VALUES (
'Scott',
SYSDATE,
10,
(SELECT REF(a) FROM addr_list1 a
WHERE VALUE(a) = address_typ('123458', 'Boston 123. ')));Пример обращения к методу:
COLUMN home.location FORMAT A20
SELECT e.ename, e.home.location, e.days_at_company() FROM emp e;
Виртуальные объекты
Переводить в существующей БД табличные описания данных в объектные не всегда возможно, а иногда и не нужно. В силу разных обстоятельств может оказаться удобной имитация объектов на основе данных, хранимых в традиционных таблицах. Тогда к одним и тем же данным можно обращаться и через объектный интерфейс, и через табличный. Достигается это с помощью виртуальных объектов (object views), которых можно так назвать по аналогии с виртуальными таблицами (views).
Для примера вернем описания и наполнение традиционным таблицам схемы SCOTT: EMP и DEPT.
(Сценарий demobld.sql выводит нас из SQL*Plus).
Упростим для примера описание типа EMPLOYEE_TYP:
ALTER TYPE employee_typ DROP ATTRIBUTE (home);
ALTER TYPE employee_typ ADD ATTRIBUTE (empno NUMBER);
ALTER TYPE employee_typ COMPILE;
Построим таблицу виртуальных объектов типа EMPLOYEE_TYP по исходным данным, хранящимся в EMP:
CREATE VIEW emp_ov OF employee_typ
WITH OBJECT IDENTIFIER (empno) AS
SELECT e.ename, e.hiredate, e.deptno, e.empno FROM emp e;По своему поведению виртуальные объекты ничем не отличаются от первичных. Проверка (“объектного доступа” к табличным данным):
SELECT e.ename, e.days_at_company () FROM emp_ov e;
SELECT VALUE(e) FROM emp_ov e;
SELECT REF(e) FROM emp_ov e;
UPDATE emp_ov e SET e.ename = INITCAP(e.ename)
WHERE e.empno = 7934;SELECT ename FROM emp_ov;
Возможность выполнения традиционных DML-операторов над базовыми таблицами, естественно, сохраняется:
Да разве б не цвела земля афинская,
Когда бы так же рассуждали граждане
И постоянно не искали нового?Аристофан, Женщины в народном собрании
Реферат
В версии Oracle 11.2 для некоторых видов объектов хранения была введена возможность заводить одновременно несколько «редакций» (editions). Она была придумана для совершенствования процесса внесения изменений в схему данных, позволяя в некоторых случаях отлаживать новый вариант приложения впараллель с работой текущего. Техника использования редакций объектов рассматривается в статье на примерах.
Содержание
Введение
- VIEW
- SYNONYM
- PROCEDURE
- FUNCTION
- TRIGGER
- PACKAGE/PACKAGE BODY
- TYPE/TYPE BODY
- LIBRARY.
Основное применение техники редакций объектов можно видеть в области и поддержки и развития приложения. Она позволяет выполнять часть работ по внесению изменений в существующее прикладное ПО без останова использования рабочей системы и отлаживать нововведения впараллель основной работе.
Хотя техника редакций объектов хранения не распространяется на данные в исходных таблицах БД, версии представлений иногда помогают подготовить приложение в том числе к переходу на новые структуры таблиц.
В версии Oracle 11.2 техника редакций объектов воплощена в своем начальном варианте, вероятно не окончательном.
Далее рассматривается несколько примеров создания и использования версий объектов в Oracle.
Подготовка схемы для редакций объектов
Ниже приводятся команды заведения в SQL*Plus схемы для объектов разных редакций и выполнения необходимых сопутствующих действий.
В схеме YARD появилась таблица EMP с той же структурой, что и одноименная в схеме SCOTT и с теми же данными (но без ограничений целостности).
Создание редакций для объектов и управление ими
Управление редакциями регулируется привилегиями CREATE/ALTER/DROP ANY EDITION. Слово ANY в названиях напоминает о внесхемном характере редакций, распространяющемся на уровень всей БД целиком (формально они все приписаны пользователю SYS).
Если правом создавать редакции объектов и управлять ими требуется доверить пользователю YARD, администратору БД следует продолжить:
Узнать действующую в данный момент редакцию можно из контекста сеанса USERENV (встроенного в СУБД):
ORA$BASE – это встроенная в БД умолчательно действующая редакция, на основе которой администратор может создавать последовательность редакций (а в будущих версиях Oracle возможно дерево) на свое усмотрение. Имя умолчательной для БД редакции можно выяснить запросом:
Примеры создания редакций:
В первом случае редакция APP_RELEASE_1 была создана на основе умолчательно действующей редакции ORA$BASE, во втором – как следует из текста команды.
Откомментировать редакцию в словаре-справочнике БД можно командой COMMENT:
Снять комментарий можно, указав пустую строку ''. Наблюдаются комментарии через таблицу ALL_EDITION_COMMENTS.
Узнать существующие редакции в их взаимосвязи можно запросом к особой таблице:
Удалить можно только лист из дерева (пока – ветки), свободный от подчиненных редакций:
Для того, чтобы пользователь Oracle мог не просто обращаться с редакциями объектов, но и формировать их, ему следует сообщить особое качество:
Качество ENABLE EDITIONS не изначальное и неотъемлемое; буде оно раз выдано, отменить его нельзя. В результате все пользователи Oracle оказываются разделены на две категории: тех, кому разрешено формировать редакции, и тех, кому не разрешено. При том возможен перевод пользователя из второй категории в первую, но никак не обратно. Удостовериться в наличие свойства ENABLE EDITIONS у пользователя можно по значению поля EDITIONS_ENABLED (нового в версии 11.2) в таблице DBA_USERS (владелец ее SYS, и обычным пользователям сама по себе она не видна).
После выдачи последней команды каждый объект пользователя YARD, для которого разрешено редактирование, так или иначе будет привязан к какой-нибудь редакции.
Настройка на работу с нужной редакцией
- он должен иметь привилегию на работу с редакцией, выданную лично ему или, вместо этого, псевдопользователю PUBLIC (то есть всем вообще);
- сеанс должен быть переключен на работу с этой редакцией.
Выдать пользователю личное общее разрешение на работу с объектами требуемой редакции можно примерно так:
USE – это привилегия на объекты вида EDITION, передаваемая к тому же через PUBLIC и через роли. Если редакцию, объявить в БД умолчательной, она автоматически полагается выданной для PUBLIC, то есть общедоступной, и не требует личных (или же ролевых) разрешений. По этой причине изначально частных разрешений на работу с ORA$BASE не требуется – оно есть у всех. То же самое произойдет с редакцией APP_RELEASE_1, если в какой-то момент выдать:
На последнюю команду способен обладатель привилегии ALTER DATABASE (а ею обладают SYS и SYSTEM, но пока что не YARD). Как только такая команда будет выдана, команды GRANT USE, как выше, для придания нужных полномочий пользователю SCOTT, не потребуется. Выдачей подобной команды может венчаться отладка новых редакций объектов («перевод приложения на новую редакцию»).
Когда пользователь Oracle получил разрешение (то есть привилегию) на работу с объектами конкретной редакции, он получает право в рамках отдельных сеансов настраиваться на нее:
Код выше подтверждает то, что по умолчанию при открытии сеанса действует редакция, объявленая ранее умолчательной в БД.
Пример создания и использования разных редакций представления данных (view)
К настоящему моменту в БД имеется две редакции. Будем формировать их содержание редакциями объектов в схеме YARD. Создадим в ней две несложные редакции одного и того же представления данных – с выдачей сведений об отделе сотрудника, и без:
Настройку на редакцию ORA$BASE можно было выше не выполнять, потому что эта редакция умолчательная (это проверялось ранее), и автоматически действует в начале каждого сеанса.
В результате появились две редакции представления данных EMP_VIEW:
Редактируемые представления данных (editioning views) отличаются от обычных не только формальным словом EDITIONING при создании, но и некоторыми техническими свойствами. Они могут строиться на основе единственной таблицы, без фильтрации строк фразой WHERE и с отсутствием преобразований столбцов (в то же время воспроизведение всех столбцов не обязательно). Есть и другие отличия, не востребованными в этом тексте.
Чтобы пользователь SCOTT имел доступ к данным, для каждой редакции требуется выдать отдельное разрешение:
Вот как этими разрешениями может воспользоваться SCOTT:
Теперь без отмены прежнего представления данных (которым может пользоваться текущее приложение) открылась возможность отлаживать приложение применительно к новому.
Упражнение. Отобрать у пользователя SCOTT привилегию на выборку данных из YARD.EMP_VIEW в редакции APP_RELEASE_1 и наблюдать результат попытки обращения.
Пример редакций процедур
Заведение разных редакций одной и той же процедуры в схеме со свойством EDITIONS_ENABLED = TRUE выглядит достаточно прозрачно. Так, для добавления данных о сотрудниках можно завести две редакции процедуры INSERT_EMPLOYEE следующим образом:
Откат транзакций сделан (а) чтобы сохранить прежние данные, и (б) в первом случае – чтобы закрыть транзакцию перед переключением на новую редакцию.
Пример редакций триггерных процедур
Теперь для добавления в БД данных о сотрудниках создадим две редакцмм триггерных процедур. Это делается аналогично обычным процедурам. Прикладной смысл триггерных процедур в данном случае состоит в нормализации имен сотрудников перед помещением в базу.
Обратите внимание, что для редактируемых представлений (EDITIONING VIEW) в триггерных процедурах не действует привязка к событию INSTEAD OF, как для обычных представлений, а вместо этого BEFORE и AFTER, как для основных таблиц. Это одно из проявлений особости редактируемых представлений от обычных.
Проверку можно выполнить следующей последовательностию команд в SQL*Plus:
Перекрестные триггерные процедуры для разных редакций
Когда отлаживается работа приложения с новой редакцией объектов БД, какое-то время обе редакции объектов (старая и новая) сосуществуют. Сложность в том, что работа с новой редакцией не должна портить данные, с которыми продолжает иметь дело старый вариант приложения. Если планируемые изменения в схеме однозначно взаимообратимы с исходным состоянием, помочь в этом способны перекрестные триггерные процедуры для разных редакций (межредакционные триггерные процедуры; crossedition triggers, CET).
Рассмотрим пример подготовки к изменению структуры таблицы EMP в схеме YARD. Предположим, требуется хранить в БД самостоятельно сведения о должностях, как например максимальную зарплату и тому подобное. Ради этого придется завести отдельную новую таблицу с данными о должностях, а в таблице EMP изъять столбец с названием должности сотрудника, и добавить заместо ссылку на сведения о должностях. Пока новая редакция приложения не будет объявлена основной, старый столбец придется какое-то время сохранять.
Подобное разбиение одной таблицы сотрудников на две – сотрудников и должностей – очевидно обратимо, так что на время отладки будет удобно воспользоваться межредакционными триггерными процедурами. Они будут отвечать при работе со старой редакцией за дублированное внесение изменений в новые структуры, а при работе с новой редакцией – в старые, обеспечивая в данных БД возможность предоставления «взгляда» на них как по-старому, так и по-новому.
Подготовка таблиц
Создадим таблицу должностей, добавим в таблицу сотрудников ссылку, при том что столбец с названием должности оставим до будущего перехода на новую редакцию приложения. Выполним в SQL*Plus:
Переименуем таблицу сотрудников, и отдадим ее старое имя двум редакциям представлений:
Создание перекрестных межредакционных триггерных процедур
Одна из создаваемых ниже триггерных процедур отвечает за правку данных, необходимую для работы старой редакции приложений, во время работы нового, а вторая наоборот. Существенно, что транслироваться обе перекрестные процедуры должны быть приписаны новой редакции:
Проверку способен организовать следующий код:
Как и раньше, если транзакция успела изменить какие-нибудь данные в БД, для настройки на новую редакцию ее потребуется сначала закрыть. В результате получим:
При работе со старой редакцией воспроизводится поведение старой таблицы EMP, а при работе с новой – с тою же таблицей, но в новом варианте.
Дополнительные замечания по технологии
Приведенные примеры перекрестных триггерных процедур были намерено упрощены. В жизни в них следовало бы предусмотреть реакцию на указание в качестве нового значения отсутствующей должности. Предположим, что в старом приложении подобная обработка не программировалась, то есть в БД добавлялась ровно то название должности, которае было указано в INSERT/UPDATE. Тогда для сохранения поведения старой реакции приложения следовало бы на возникающую в SELECT . INTO . FROM job ошибку NO_DATA_FOUND среагировать добавлением новой записи в таблицу JOB. Придется решить технический вопрос о поставке значений в JOBID; это может потребовать употребления генератора последовательности (sequence) и других усложнений.
При решении перейти на новую редакцию приложения перекрестные триггерные процедуры и редакционные представления данных следует удалить, а освободившееся имя EMP вернуть основной таблице:
Object-oriented programming is especially suited for building reusable components and complex applications. In PL/SQL, object-oriented programming is based on object types. They let you model real-world objects, separate interfaces and implementation details, and store object-oriented data persistently in the database.
This chapter contains these topics:
Using Dynamic SQL With Objects
Example 12-18 illustrates the use of objects and collections with dynamic SQL. First, define object type person_typ and VARRAY type hobbies_var , then write a package that uses these types.
Example 12-18 TEAMS Package Using Dynamic SQL for Object Types and Collections
From an anonymous block, you might call the procedures in package TEAMS :
Объектно-ориентированное программирование особенно подходит для создания многократно используемых компонентов и сложных приложений. Они организованы вокруг «объектов», а не «действий», т.е. программы предназначены для работы и взаимодействия со всем объектом, а не с одним действием. Эта концепция позволяет программисту заполнять и манипулировать деталями на уровне объектов объекта.
Ниже на рисунке изображен пример типа объекта, в котором банковский счет считается объектом объекта. Атрибуты объекта включают вещи, которые содержат некоторые значения атрибутов, например, в банковском счете; это номер счета, баланс банка и т. д., в то время как методы объекта описывают такие вещи, как расчет процентной ставки, формирование выписки по счету и т. д., которые требуют выполнения определенного процесса.
В PL / SQL объектно-ориентированное программирование основано на объектных типах.
Тип объекта может представлять любую сущность реального мира. Мы собираемся обсудить больше типов объектов в этой главе.
В этом уроке – вы узнаете,
How PL/SQL Treats Uninitialized Objects
Until you initialize an object by calling the constructor for its object type, the object is atomically null. That is, the object itself is null, not just its attributes.
A null object is never equal to another object. In fact, comparing a null object with any other object always yields NULL . Also, if you assign an atomically null object to another object, the other object becomes atomically null (and must be reinitialized). Likewise, if you assign the non-value NULL to an object, the object becomes atomically null.
In an expression, attributes of an uninitialized object evaluate to NULL . When applied to an uninitialized object or its attributes, the IS NULL comparison operator yields TRUE .
Example 12-3 illustrates null objects and objects with null attributes.
Example 12-3 Null Objects in a PL/SQL Block
Calls to methods of an uninitialized object raise the predefined exception NULL_SELF_DISPATCH . When passed as arguments to IN parameters, attributes of an uninitialized object evaluate to NULL . When passed as arguments to OUT or IN OUT parameters, they raise an exception if you try to write to them.
Defining SQL Types Equivalent to PL/SQL Collection Types
To store nested tables and varrays inside database tables, you must also declare SQL types using the CREATE TYPE statement. The SQL types can be used as columns or as attributes of SQL object types. For information on the CREATE TYPE SQL statement, see Oracle Database SQL Reference . For information on the CREATE TYPE BODY SQL statement, see Oracle Database SQL Reference . For more information on object types, see Oracle Database Application Developer's Guide - Object-Relational Features .
You can declare equivalent types within PL/SQL, or use the SQL type name in a PL/SQL variable declaration.
Example 12-10 shows how you might declare a nested table in SQL, and use it as an attribute of an object type.
Example 12-10 Declaring a Nested Table in SQL
The identifier courses represents an entire nested table. Each element of courses stores the name of a college course such as 'Math 1020' .
Example 12-11 creates a database column that stores varrays. Each varray element contains a VARCHAR2 .
Example 12-11 Creating a Table with a Varray Column
In Example 12-12, you insert a row into database table dept_projects . The varray constructor ProjectList() provides a value for column projects .
Example 12-12 Varray Constructor Within a SQL Statement
In Example 12-13, you insert several scalar values and a CourseList nested table into the sophomores table.
Example 12-13 Nested Table Constructor Within a SQL Statement
Атрибуты
Атрибуты – это столбец или поле, в котором хранятся данные. Каждый атрибут будет сопоставлен с типом данных, который определяет тип обработки и хранения для этого атрибута. Атрибут может иметь любой допустимый тип данных PL / SQL или другой тип объекта.
Объектные типы данных в Oracle
Помимо сравнительно простых встроенных типов данных — как перешедших из стандартов SQL , так и собственных, — в Oracle имеется возможность использовать составные. Это конструируемые типы объектов, рассчитанные на хранение в БД данных, имеющих внутреннюю структуру. Эта структура известна СУБД , и СУБД позволяет с ней работать. Объектные типы позволяют хранить и обрабатывать средствами СУБД "сложно устроенные данные" более продвинутым образом, нежели это позволяет техника "больших неструктурированных объектов" типов LOB . Ввиду наличия вполне определенного типа (даже если это тип коллекции ), единичное объектное значение можно полагать за скаляр, хотя оно и не будет атомарным.
Хранение в столбцах таблицы значений в виде объектов, в смысле объектного подхода (ОП в программировании и моделировании), фирма Oracle впервые обеспечила в рамках так называемой "объектно-реляционной модели" начиная с версии Oracle 8. Некоторые существенные пробелы первой реализации (например, отсутствие наследования типов ) были устранены в версии 9. Примеры ниже не выходят за рамки возможностей версии 9.2, позже которой, впрочем, никаких существенных нововведений по объектной части не наблюдалось. Объектные возможности Oracle в общем следуют определениям SQL :1999, однако делают это непунктуально.
Программируемые типы данных и объекты в БД
Простой пример
Ниже приводится простой пример использования программируемых (объектных) типов.
Вначале требуется создать "тип", как разновидности хранимых элементов БД. Пример создания типа объекта (в SQL*Plus):
Здесь типу ADDRESS_TYPE приписаны два "свойства" (по объектной терминологии): ZIP и LOCATION . В реальной жизни для представления адреса в типе наверняка будет указано большее количество свойств, однако в ознакомительном примере их более пространный перечень излишен и не добавит понимания техники.
Определение типа напоминает определение таблицы, однако в отличие от таблицы (а также стандарта SQL и от реляционного подхода) тип объекта в Oracle не имеет права содержать ограничений целостности (которые в таком случае можно было бы назвать "ограничениями целостности типа"). Если необходимо их указать, сделать это придется только по месту употребления типа, то есть в описании таблицы.
В соответствии с традициями объектного подхода (уместно вспомнить, что "объектной теории", в отличие от реляционной, не создано) Oracle разрешает использовать тип для создания "буквальных значений" и собственно объектов. Далее приводится сначала несколько примеров первого, а затем второго.
"Буквальные значения" фактически позволяют работать со значениями, обладающими известной СУБД структурой и однозначно определяются набором значений элементов своей структуры.
Примеры использования типа ADDRESS_TYPE для определения столбца в обычной таблице:
Столбцы ADDR и HOME можно с некоторой вольностью назвать "объектными атрибутами". Они не позволяют хранить объектные значения в виде самостоятельной сущности и ссылаться на них ссылками. Локализовать такие значения можно только по обычным правилам поиска данных в таблице.
В выражениях явно указанные объектные значения формулируются с помощью конструктора. В отличие от других объектных систем, например, от Java, в Oracle конструктор умолчательно имеет список параметров, соответствующих свойствам типа. Примеры применения в операциях добавления данных:
Oracle допускает определенные синтаксические вольности в записи выражения над объектными данными. Здесь и далее используются частные случаи возможных формулировок.
Пример применения в запросе о сотрудниках, "работающих по месту жительства", за исключением конкретно указанного адреса:
Пример показывает легкость формулирования сравнения составных величин, каковыми являются адреса. Сравнение осуществляется поэлементно, путем сравнением всех свойств по очереди. Увы, но простота формулировки не дает права программисту расслабляться и забывать об особых случаях сравнения с данными типа CHAR и с NULL . Так, присутствие NULL в буквальных объектных значениях запутывает проблему сравнения еще больше, чем для случая простых типов. Сравните:
То есть получается, что x = x не дает TRUE , но притом x IS NOT NULL дает TRUE ( x имеет значение).
В выражениях можно обращаться к буквальному объектному значению как к целому, а можно и к его отдельным свойствам. Во втором случае, как правило, требуется прибегать к псевдониму:
Таблицы объектов
Созданный в БД тип можно употребить и для создания "таблиц объектов":
Хотя для этой категории хранимых элементов используется термин "таблица", такая таблица всегда содержит ровно один столбец, и именно объектного типа.
Запись занесения "строк" в такую таблицу может быть, в частности, такой:
SELECT a.*, UPPER ( location ) FROM addresses1 a;
Объекты в таких таблицах хранятся как самостоятельные сущности, у которых имеется автоматически порождаемый СУБД внутренний уникальный идентификатор object ID, в соответствии с классическим объектным подходом позволяющий ссылаться на конкретные объекты из других таблиц или из программы. Сравнение элементов-"строк" в таблице объектов друг с другом происходит уже не по значениям свойств, как в случае объектного столбца в обычной таблице, а по значению object ID. Перейти на сравнение значений свойств позволяет функция VALUE, например:
Сделан запрос об отделах, расположенных по адресам из таблицы ADDRESS1 .
Не исключено, что создатели функции VALUE обсуждали другое ее название — LITERAL_VALUE . По крайней мере, оно точнее описывает совершаемое действие: создание значения со структурой из объекта. Буквальные значения сравниваются друг с другом по значениям их свойств, а объекты — по значениям object ID.
В версии 8 в Oracle появилась возможность хранения неатомарных (нескалярных) значений в поле таблицы, а именно объекта в смысле объектного подхода (в рамках так называемой “объектно-реляционной модели” Oracle). Некоторые существенные пробелы этой первой реализации были устранены в версии 9. Примеры ниже используют возможности версии 9.2.
Сразу надо предостеречь от преувеличений достоинств объектного подхода в базах данных вообще. Действительно, неискушенный читатель некоторых руководств или рекламных материалов быстро впадет в недоумение: зачем же такие маститые разработчики СУБД, как фирмы IBM, Informix или Oracle так долго занимались табличной организацией данных, когда все это время рядом существовала более совершенная, удобная и т. д. объектная, первая реализация которой фирмой Xerox известна с 1980 года?
Непредвзятый ответ состоит в том, что ни табличная организация (часто вольно называемая “реляционной” применительно к конкретным СУБД), ни объектная не являются универсально “хорошими”, и что имеются свои достоинства и недостатки у одной и у другой. Некоторые соображения относительно областей применения обоих подходов к хранению данных можно найти в статье “Что объектам здорово, то реляциям смерть, и наоборот, и еще пол-оборота”.
В целом объектная реализация в Oracle традиционна для объектного подхода вообще. В основе лежит понятие объекта как совокупности свойств (атрибутов), причем действия с объектом регламентируются формулируемым набором методов (процедур или функций). Тип объекта задается сохраняемым в БД объектом TYPE.
Хранимые объекты
Простой пример
Рассмотрим схему БД, где хранятся данные о сотрудниках и отделах. Будем работать в схеме SCOTT, из которой на время нужно удалить таблицы EMP и DEPT (позже мы их восстановим).
Предположим, что и те, и другие имеют адреса: сотрудники - домашний, а отделы – юридический. Адрес имеет несколько полей (например, “индекс”, “район”, “населенный пункт”, “место”). В традиционной табличной реализации есть два способа промоделировать наличие адреса:
- включить одинаковые группы полей в таблицы сотрудников и отделов;
- создать отдельную таблицу адресов и включить в таблицы сотрудников и отделов ссылки на нее.Первое решение неудобно тем, что адрес теряет свою идентичность: неудобно, например, сравнивать адреса, особенно в разных таблицах. Второе решение искусственно, если только не считать адреса самостоятельными объектами моделирования.
Объектные возможности последних версий Oracle дают возможность более приемлемой альтернативы. Для описания адреса создадим тип (здесь и далее предполагается использование в качестве рабочего инструмента SQL*Plus):
CREATE TYPE address_typ AS OBJECT (
zip CHAR(6),
location VARCHAR2(200))
/Воспользуемся этим типом для описания сотрудников и отделов:
CREATE TABLE dept (
dname VARCHAR2(50),
deptno NUMBER CONSTRAINT pk_dept PRIMARY KEY,
addr address_typ);CREATE TABLE emp (
ename VARCHAR2(50),
empno NUMBER CONSTRAINT pk_emp PRIMARY KEY,
deptno NUMBER CONSTRAINT fk_emp REFERENCES dept,
home address_typ);Проверим описания созданных объектов:
DESCRIBE address_typ
DESCRIBE dept
DESCRIBE empПример заведения сотрудников и отделов:
INSERT INTO dept VALUES (
'Sales',
10,
address_typ('123456', 'Boston 123. '));INSERT INTO emp VALUES (
'Smith',
1001,
10,
address_typ('123333', 'Boston 567. '));Здесь выражение ADDRESS_TYP('123333', 'Boston 567. ') означает обращение к конструктору объекта, то есть к функции, автоматически создаваемой СУБД при заведении нового типа для возможности создавать новые объекты этого типа с нужными значениями атрибутов. Понятие конструктора общепринято в объектном подходе. В приведенных предложениях INSERT простановку адреса можно оформить чуть иначе, добавив, в соответствии с духом объектного подхода, ключевое слово NEW перед обращением к конструктору:
INSERT INTO emp VALUES (
'Allen',
1002,
10,
NEW address_typ('123456', 'Boston 123. '));COLUMN dname FORMAT A20
COLUMN ename FORMAT A20
COLUMN addr FORMAT A40
COLUMN home FORMAT A40SELECT * FROM dept;
SELECT * FROM emp;
SELECT ename, home FROM emp;
SELECT e.ename, d.dname FROM emp e, dept d WHERE e.home = d.addr;
SELECT e.ename, e.home.zip FROM emp e;
UPDATE emp
SET home = address_typ('123457', 'Boston 777. ')
WHERE ename = 'Allen';UPDATE emp e SET e.home.zip = '123458' WHERE ename = 'Allen';
Создание таблицы объектов
Если адрес интересует нас как самостоятельная сущность, а не атрибут прочих сущностей, созданный для адреса тип можно использовать для создания таблиц объектов:
CREATE TABLE addr_list1 OF address_typ;
CREATE TABLE addr_list2 OF address_typ;
Таблицы объектов в Oracle было бы точнее называть списками объектов, так как это всегда таблицы ровно из одного столбца объектного типа.
Заполнение данными происходит как и ранее:
INSERT INTO addr_list1 VALUES
(NEW address_typ('123456', 'Boston 123. '));INSERT INTO addr_list1 VALUES
(address_typ('123458', 'Boston 123. '));INSERT INTO addr_list2 VALUES
(address_typ('123333', 'Boston 567. '));COLUMN location FORMAT A30
SELECT * FROM addr_list1;
SELECT VALUE(a) FROM addr_list1 a;
SELECT e.ename, e.home
FROM addr_list1 a, emp e
WHERE VALUE(a) = e.home;(Функция VALUE специально придумана для возвращения значений объектов, а не атрибутов объектов по отдельности).
Ссылки на объект
Объекты, заведенные в объектных таблицах, имеют одно преимущество перед объектами, указанными как атрибут строки: на них можно ссылаться. Ссылка есть уникальный внутренний идентификатор объекта, и получить его можно с помощью функции REF:
COLUMN ref FORMAT A90
COLUMN value FORMAT A40SELECT REF(a) ref, VALUE(a) FROM addr_list1 a;
Теперь можно поменять описание таблицы, например, DEPT, чтобы она заимствовала адреса отделов из имеющегося списка, а не хранила вместе со своими данными:
ALTER TABLE dept DROP (addr);
ALTER TABLE dept ADD (addr REF address_typ SCOPE IS addr_list1);
SELECT * FROM dept;
UPDATE dept d
SET d.addr =
(SELECT REF(a)
FROM addr_list1 a
WHERE VALUE(a)= address_typ('123458', 'Boston 123. '))
WHERE d.deptno = 10;SELECT * FROM dept;
Фраза SCOPE IS при определении типа как ссылки на существующий объект необязательна, но позволяет фактически ссылаться только на объекты какой-нибудь объектной таблицы.
Раскрытие ссылки делается с помощью специальной функции DEREF:
COLUMN deref(addr) FORMAT A40
SELECT d.dname, DEREF(addr) FROM dept d;
Однако при обращении к нижележащим атрибутам раскрытие может выполняться и неявно (неявное преобразование типов, присутствующее в Oracle-диалекте SQL):
SELECT d.dname, d.addr.zip FROM dept d;
вместо более правильного
SELECT d.dname, DEREF(d.addr).zip FROM dept d;
Методы объектов
Выше было рассмотрено определение типа, содержащее описание атрибутов (“свойств”). Создадим тип сотрудников, в котором определен еще и метод:
CREATE TYPE employee_typ AS OBJECT (
ename VARCHAR2(50),
hiredate DATE,
deptno NUMBER,
home REF address_typ,
MEMBER FUNCTION days_at_company RETURN NUMBER)
/Для описания тела метода-функции необходимо создать тело типа (аналогия пакет – тело пакета в PL/SQL):
CREATE TYPE BODY employee_typ IS
MEMBER FUNCTION days_at_company RETURN NUMBER IS
BEGIN
RETURN TRUNC(SYSDATE-hiredate);
END;
END;
/Создадим таблицу объектов-сотрудников:
CREATE TABLE emp OF employee_typ;
INSERT INTO emp VALUES (
'Scott',
SYSDATE,
10,
(SELECT REF(a) FROM addr_list1 a
WHERE VALUE(a) = address_typ('123458', 'Boston 123. ')));Пример обращения к методу:
COLUMN home.location FORMAT A20
SELECT e.ename, e.home.location, e.days_at_company() FROM emp e;
Виртуальные объекты
Переводить в существующей БД табличные описания данных в объектные не всегда возможно, а иногда и не нужно. В силу разных обстоятельств может оказаться удобной имитация объектов на основе данных, хранимых в традиционных таблицах. Тогда к одним и тем же данным можно обращаться и через объектный интерфейс, и через табличный. Достигается это с помощью виртуальных объектов (object views), которых можно так назвать по аналогии с виртуальными таблицами (views).
Для примера вернем описания и наполнение традиционным таблицам схемы SCOTT: EMP и DEPT.
(Сценарий demobld.sql выводит нас из SQL*Plus).
Упростим для примера описание типа EMPLOYEE_TYP:
ALTER TYPE employee_typ DROP ATTRIBUTE (home);
ALTER TYPE employee_typ ADD ATTRIBUTE (empno NUMBER);
ALTER TYPE employee_typ COMPILE;
Построим таблицу виртуальных объектов типа EMPLOYEE_TYP по исходным данным, хранящимся в EMP:
CREATE VIEW emp_ov OF employee_typ
WITH OBJECT IDENTIFIER (empno) AS
SELECT e.ename, e.hiredate, e.deptno, e.empno FROM emp e;По своему поведению виртуальные объекты ничем не отличаются от первичных. Проверка (“объектного доступа” к табличным данным):
SELECT e.ename, e.days_at_company () FROM emp_ov e;
SELECT VALUE(e) FROM emp_ov e;
SELECT REF(e) FROM emp_ov e;
UPDATE emp_ov e SET e.ename = INITCAP(e.ename)
WHERE e.empno = 7934;SELECT ename FROM emp_ov;
Возможность выполнения традиционных DML-операторов над базовыми таблицами, естественно, сохраняется:
Да разве б не цвела земля афинская,
Когда бы так же рассуждали граждане
И постоянно не искали нового?Аристофан, Женщины в народном собрании
Реферат
В версии Oracle 11.2 для некоторых видов объектов хранения была введена возможность заводить одновременно несколько «редакций» (editions). Она была придумана для совершенствования процесса внесения изменений в схему данных, позволяя в некоторых случаях отлаживать новый вариант приложения впараллель с работой текущего. Техника использования редакций объектов рассматривается в статье на примерах.
Содержание
Введение
- VIEW
- SYNONYM
- PROCEDURE
- FUNCTION
- TRIGGER
- PACKAGE/PACKAGE BODY
- TYPE/TYPE BODY
- LIBRARY.
Основное применение техники редакций объектов можно видеть в области и поддержки и развития приложения. Она позволяет выполнять часть работ по внесению изменений в существующее прикладное ПО без останова использования рабочей системы и отлаживать нововведения впараллель основной работе.
Хотя техника редакций объектов хранения не распространяется на данные в исходных таблицах БД, версии представлений иногда помогают подготовить приложение в том числе к переходу на новые структуры таблиц.
В версии Oracle 11.2 техника редакций объектов воплощена в своем начальном варианте, вероятно не окончательном.
Далее рассматривается несколько примеров создания и использования версий объектов в Oracle.
Подготовка схемы для редакций объектов
Ниже приводятся команды заведения в SQL*Plus схемы для объектов разных редакций и выполнения необходимых сопутствующих действий.
В схеме YARD появилась таблица EMP с той же структурой, что и одноименная в схеме SCOTT и с теми же данными (но без ограничений целостности).
Создание редакций для объектов и управление ими
Управление редакциями регулируется привилегиями CREATE/ALTER/DROP ANY EDITION. Слово ANY в названиях напоминает о внесхемном характере редакций, распространяющемся на уровень всей БД целиком (формально они все приписаны пользователю SYS).
Если правом создавать редакции объектов и управлять ими требуется доверить пользователю YARD, администратору БД следует продолжить:
Узнать действующую в данный момент редакцию можно из контекста сеанса USERENV (встроенного в СУБД):
ORA$BASE – это встроенная в БД умолчательно действующая редакция, на основе которой администратор может создавать последовательность редакций (а в будущих версиях Oracle возможно дерево) на свое усмотрение. Имя умолчательной для БД редакции можно выяснить запросом:
Примеры создания редакций:
В первом случае редакция APP_RELEASE_1 была создана на основе умолчательно действующей редакции ORA$BASE, во втором – как следует из текста команды.
Откомментировать редакцию в словаре-справочнике БД можно командой COMMENT:
Снять комментарий можно, указав пустую строку ''. Наблюдаются комментарии через таблицу ALL_EDITION_COMMENTS.
Узнать существующие редакции в их взаимосвязи можно запросом к особой таблице:
Удалить можно только лист из дерева (пока – ветки), свободный от подчиненных редакций:
Для того, чтобы пользователь Oracle мог не просто обращаться с редакциями объектов, но и формировать их, ему следует сообщить особое качество:
Качество ENABLE EDITIONS не изначальное и неотъемлемое; буде оно раз выдано, отменить его нельзя. В результате все пользователи Oracle оказываются разделены на две категории: тех, кому разрешено формировать редакции, и тех, кому не разрешено. При том возможен перевод пользователя из второй категории в первую, но никак не обратно. Удостовериться в наличие свойства ENABLE EDITIONS у пользователя можно по значению поля EDITIONS_ENABLED (нового в версии 11.2) в таблице DBA_USERS (владелец ее SYS, и обычным пользователям сама по себе она не видна).
После выдачи последней команды каждый объект пользователя YARD, для которого разрешено редактирование, так или иначе будет привязан к какой-нибудь редакции.
Настройка на работу с нужной редакцией
- он должен иметь привилегию на работу с редакцией, выданную лично ему или, вместо этого, псевдопользователю PUBLIC (то есть всем вообще);
- сеанс должен быть переключен на работу с этой редакцией.
Выдать пользователю личное общее разрешение на работу с объектами требуемой редакции можно примерно так:
USE – это привилегия на объекты вида EDITION, передаваемая к тому же через PUBLIC и через роли. Если редакцию, объявить в БД умолчательной, она автоматически полагается выданной для PUBLIC, то есть общедоступной, и не требует личных (или же ролевых) разрешений. По этой причине изначально частных разрешений на работу с ORA$BASE не требуется – оно есть у всех. То же самое произойдет с редакцией APP_RELEASE_1, если в какой-то момент выдать:
На последнюю команду способен обладатель привилегии ALTER DATABASE (а ею обладают SYS и SYSTEM, но пока что не YARD). Как только такая команда будет выдана, команды GRANT USE, как выше, для придания нужных полномочий пользователю SCOTT, не потребуется. Выдачей подобной команды может венчаться отладка новых редакций объектов («перевод приложения на новую редакцию»).
Когда пользователь Oracle получил разрешение (то есть привилегию) на работу с объектами конкретной редакции, он получает право в рамках отдельных сеансов настраиваться на нее:
Код выше подтверждает то, что по умолчанию при открытии сеанса действует редакция, объявленая ранее умолчательной в БД.
Пример создания и использования разных редакций представления данных (view)
К настоящему моменту в БД имеется две редакции. Будем формировать их содержание редакциями объектов в схеме YARD. Создадим в ней две несложные редакции одного и того же представления данных – с выдачей сведений об отделе сотрудника, и без:
Настройку на редакцию ORA$BASE можно было выше не выполнять, потому что эта редакция умолчательная (это проверялось ранее), и автоматически действует в начале каждого сеанса.
В результате появились две редакции представления данных EMP_VIEW:
Редактируемые представления данных (editioning views) отличаются от обычных не только формальным словом EDITIONING при создании, но и некоторыми техническими свойствами. Они могут строиться на основе единственной таблицы, без фильтрации строк фразой WHERE и с отсутствием преобразований столбцов (в то же время воспроизведение всех столбцов не обязательно). Есть и другие отличия, не востребованными в этом тексте.
Чтобы пользователь SCOTT имел доступ к данным, для каждой редакции требуется выдать отдельное разрешение:
Вот как этими разрешениями может воспользоваться SCOTT:
Теперь без отмены прежнего представления данных (которым может пользоваться текущее приложение) открылась возможность отлаживать приложение применительно к новому.
Упражнение. Отобрать у пользователя SCOTT привилегию на выборку данных из YARD.EMP_VIEW в редакции APP_RELEASE_1 и наблюдать результат попытки обращения.
Пример редакций процедур
Заведение разных редакций одной и той же процедуры в схеме со свойством EDITIONS_ENABLED = TRUE выглядит достаточно прозрачно. Так, для добавления данных о сотрудниках можно завести две редакции процедуры INSERT_EMPLOYEE следующим образом:
Откат транзакций сделан (а) чтобы сохранить прежние данные, и (б) в первом случае – чтобы закрыть транзакцию перед переключением на новую редакцию.
Пример редакций триггерных процедур
Теперь для добавления в БД данных о сотрудниках создадим две редакцмм триггерных процедур. Это делается аналогично обычным процедурам. Прикладной смысл триггерных процедур в данном случае состоит в нормализации имен сотрудников перед помещением в базу.
Обратите внимание, что для редактируемых представлений (EDITIONING VIEW) в триггерных процедурах не действует привязка к событию INSTEAD OF, как для обычных представлений, а вместо этого BEFORE и AFTER, как для основных таблиц. Это одно из проявлений особости редактируемых представлений от обычных.
Проверку можно выполнить следующей последовательностию команд в SQL*Plus:
Перекрестные триггерные процедуры для разных редакций
Когда отлаживается работа приложения с новой редакцией объектов БД, какое-то время обе редакции объектов (старая и новая) сосуществуют. Сложность в том, что работа с новой редакцией не должна портить данные, с которыми продолжает иметь дело старый вариант приложения. Если планируемые изменения в схеме однозначно взаимообратимы с исходным состоянием, помочь в этом способны перекрестные триггерные процедуры для разных редакций (межредакционные триггерные процедуры; crossedition triggers, CET).
Рассмотрим пример подготовки к изменению структуры таблицы EMP в схеме YARD. Предположим, требуется хранить в БД самостоятельно сведения о должностях, как например максимальную зарплату и тому подобное. Ради этого придется завести отдельную новую таблицу с данными о должностях, а в таблице EMP изъять столбец с названием должности сотрудника, и добавить заместо ссылку на сведения о должностях. Пока новая редакция приложения не будет объявлена основной, старый столбец придется какое-то время сохранять.
Подобное разбиение одной таблицы сотрудников на две – сотрудников и должностей – очевидно обратимо, так что на время отладки будет удобно воспользоваться межредакционными триггерными процедурами. Они будут отвечать при работе со старой редакцией за дублированное внесение изменений в новые структуры, а при работе с новой редакцией – в старые, обеспечивая в данных БД возможность предоставления «взгляда» на них как по-старому, так и по-новому.
Подготовка таблиц
Создадим таблицу должностей, добавим в таблицу сотрудников ссылку, при том что столбец с названием должности оставим до будущего перехода на новую редакцию приложения. Выполним в SQL*Plus:
Переименуем таблицу сотрудников, и отдадим ее старое имя двум редакциям представлений:
Создание перекрестных межредакционных триггерных процедур
Одна из создаваемых ниже триггерных процедур отвечает за правку данных, необходимую для работы старой редакции приложений, во время работы нового, а вторая наоборот. Существенно, что транслироваться обе перекрестные процедуры должны быть приписаны новой редакции:
Проверку способен организовать следующий код:
Как и раньше, если транзакция успела изменить какие-нибудь данные в БД, для настройки на новую редакцию ее потребуется сначала закрыть. В результате получим:
При работе со старой редакцией воспроизводится поведение старой таблицы EMP, а при работе с новой – с тою же таблицей, но в новом варианте.
Дополнительные замечания по технологии
Приведенные примеры перекрестных триггерных процедур были намерено упрощены. В жизни в них следовало бы предусмотреть реакцию на указание в качестве нового значения отсутствующей должности. Предположим, что в старом приложении подобная обработка не программировалась, то есть в БД добавлялась ровно то название должности, которае было указано в INSERT/UPDATE. Тогда для сохранения поведения старой реакции приложения следовало бы на возникающую в SELECT . INTO . FROM job ошибку NO_DATA_FOUND среагировать добавлением новой записи в таблицу JOB. Придется решить технический вопрос о поставке значений в JOBID; это может потребовать употребления генератора последовательности (sequence) и других усложнений.
При решении перейти на новую редакцию приложения перекрестные триггерные процедуры и редакционные представления данных следует удалить, а освободившееся имя EMP вернуть основной таблице:
Object-oriented programming is especially suited for building reusable components and complex applications. In PL/SQL, object-oriented programming is based on object types. They let you model real-world objects, separate interfaces and implementation details, and store object-oriented data persistently in the database.
This chapter contains these topics:
Читайте также: