Объектные представления Oracle для программирования PL/SQL

Объектные представления Oracle для программирования PL/SQL

Продолжаем рассматривать объектно-ориентированные возможности PL/SQL и СУБД Oracle. Объектные расширения Oracle предоставляют программистам PL/SQL богатые воз­можности для разработки новых систем, однако маловероятно, что ради них вы захотите полностью перепроектировать старые системы. Чтобы существующие приложения могли использовать преимущества новых объектных функций, в Oracle реализованы объектные представления, обладающие рядом уникальных преимуществ.



  • Объектное представление удаленных данных. В Oracle9i еще не поддерживаются объектные таблицы и физические REF-ссылки в распределенных базах данных, но можно создавать объектные представления и виртуальные REF-ссылки, представ­ляющие удаленные данные реляционных баз как объекты.
  • Виртуальная денормализация. В реляционной или даже объектно-реляционной базе данных обычно реализуются однонаправленные отношения. Например, книга  относится к определенному количеству категорий. Объектные представления по­зволяют установить обратное соответствие; в частности объект-категория может включать коллекцию REF-ссылок, указывающих на все книги этой категории.
  • Эффективность доступа к объектам. В приложениях OCI (Oracle Call Interface) могут использоваться программные конструкции, обеспечивающие удобное из­влечение, кэширование и обновление объектных данных. Сокращая количество обращений приложения к серверу базы данных, они повышают производительность и, кроме того, делают код более лаконичным.
  • Большая гибкость в отношении изменения объектной модели. Хотя в новых верси­ях Oracle имеются прекрасные возможности в области эволюции типов, добавление и удаление атрибутов объектов по-прежнему сопряжено с перемещением таблицы по диску, чего администраторы баз данных очень не любят. Перекомпиляция объ­ектных представлений не имеет таких последствий.

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

  • Производительность. Объектные представления обрабатываются не так быстро, как этого хотелось бы.
  • Виртуальные ссылки. Виртуальные ссылки не хранятся в базе данных, а создаются в ходе выполнения программы. Это может вызвать определенные проблемы, если однажды вы вдруг захотите преобразовать объектные представления в объектные таблицы.

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

  • Коллекции. Если взять две реляционные таблицы, связанные отношением «глав­ная — подчиненная», можно создать для них представление, возвращающее строки подчиненной таблицы в виде одного нескалярного атрибута (коллекции) строки главной таблицы.
  • Триггеры INSTEAD OF. С помощью триггера INSTEAD OF можно указать Oracle, как именно должны выполняться операции вставки, обновления и удаления данных в представлениях.

Объектные представления

Рис. 1. Объектные представления позволяют связать определения объектных типов с (существующими) реляционными таблицами

С точки зрения объектной теории объектные представления имеют один второстепенный недостаток — они не обеспечивают инкапсуляции. Поскольку приложение применяет команды INSERT, UPDATE, MERGE и DELETE непосредственно к содержимому реляционных баз данных, это отменяет все преимущества инкапсуляции, обычно присущие объектному подходу. Но поскольку Oracle все равно не поддерживает ни приватных атрибутов, ни приватных методов, потеря невелика.

Если вы решили наложить объектные представления поверх существующей системы, может оказаться, что новые приложения будут пользоваться дополнительными преиму­ществами, а унаследованные системы будут работать так же, как прежде. Применение объектных представлений проиллюстрировано на рис. 1.

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

 

Пример реляционной системы

Во втором крупном примере этой предыдущего блога мы рассмотрим применение объектных пред­ставлений в приложении базы данных компании, занимающейся графическим дизайном. Реляционное приложение используется для работы с информацией об используемых изображениях (GIF, JPEG и т. д.). Изображения хранятся в файлах, но информация о них содержится в таблицах базы данных. Чтобы художнику легче было искать нужные изображения, с каждым из них связывается одно или несколько ключевых слов. Данные об изображениях и ключевые слова хранятся в двух таблицах, связанных отношением «главная — подчиненная».

В базе данных имеется таблица поставщиков изображений:

CREATE TABLE suppliers (
   id INTEGER NOT NULL PRIMARY KEY,
   name VARCHAR2(400) NOT NULL
);

Также имеется таблица метаданных изображений:

CREATE TABLE images (
   image_id INTEGER NOT NULL PRIMARY KEY,
   file_name VARCHAR2(512) NOT NULL,
   file_type VARCHAR2(12) NOT NULL,
   supplier_id INTEGER REFERENCES suppliers (id),
   supplier_rights_descriptor VARCHAR2(256),
   bytes INTEGER
);

Однако не все изображения поступают от поставщиков; если идентификатор поставщика (supplier_id) равен NULL, значит, изображение создано работниками самой компании. В базе данных имеется еще одна таблица, которая содержит ключевые слова, связанные с изображениями:

CREATE TABLE keywords (
   image_id INTEGER NOT NULL REFERENCES images (image_id),
   keyword VARCHAR2(45) NOT NULL,
   CONSTRAINT keywords_pk PRIMARY KEY (image_id, keyword)
);

Предположим, таблицы заполнены следующими данными:

INSERT INTO suppliers VALUES (101, 'Joe''s Graphics');
INSERT INTO suppliers VALUES (102, 'Image Bar and Grill');
INSERT INTO images VALUES (100001, '/files/web/60s/smiley_face.png', 
  'image/png', 101, 'fair use', 813);
INSERT INTO images VALUES (100002, '/files/web/60s/peace_symbol.gif', 
  'image/gif', 101, 'fair use', 972);
INSERT INTO images VALUES (100003, '/files/web/00s/towers.jpg',
 'image/jpeg', NULL,
   NULL, 2104);
INSERT INTO KEYWORDS VALUES (100001, 'SIXTIES');
INSERT INTO KEYWORDS VALUES (100001, 'HAPPY FACE');
INSERT INTO KEYWORDS VALUES (100002, 'SIXTIES');
INSERT INTO KEYWORDS VALUES (100002, 'PEACE SYMBOL');
INSERT INTO KEYWORDS VALUES (100002, 'JERRY RUBIN');

В следующих разделах описываются объектные представления, определенные на основе этих данных:

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

 

Объектное представление с атрибутом-коллекцией

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

CREATE TYPE keyword_tab_t AS TABLE OF VARCHAR2(45);
At this point, it’s a simple matter to define the image object type:

CREATE TYPE image_t AS OBJECT (
    image_id INTEGER,
    image_file BFILE,
    file_type VARCHAR2(12),
    bytes INTEGER,
    keywords keyword_tab_t
);

Если файлы изображений и сервер базы данных располагаются на одном компьютере, то вместо имени файла можно использовать тип данных BFILE. Нужно создать «каталог», то есть используемый только в Oracle псевдоним каталога операционной системы, в ко­тором хранятся изображения. Зададим корневой каталог, поскольку в столбце file_name указаны полные пути к файлам.

CREATE DIRECTORY rootdir AS '/';

Внимание! Скорее всего, вы не будете обладать привилегиями для работы с файлами в кор­невом каталоге; укажите тот каталог, с которым вы можете работать.

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

CREATE VIEW images_v
   OF image_t
   WITH OBJECT IDENTIFIER (image_id)
AS
   SELECT i.image_id, BFILENAME('ROOTDIR', i.file_name),
      i.file_type, i.bytes,
      CAST (MULTISET (SELECT keyword
                        FROM keywords k
                       WHERE k.image_id = i.image_id)
        AS keyword_tab_t)
     FROM images i;

 Если порядок важен или максимальное количество ключевых слов ограничено (относительно небольшим числом), лучше использовать коллекцию типа VARRAY.

Два компонента этой команды характерны только для объектных представлений:

  • OF image_t — означает, что будут возвращены объекты типа image_t.
  • WITH OBJECT IDENTIFIER (image_id) — чтобы возвращаемые в представлении данные были похожи на настоящие экземпляры объектов, им нужен объектный иденти­фикатор. Определив первичный ключ как основу для виртуального OID, можно пользоваться преимуществами REF-навигации по объектам представления.

Итак, объектное представление создано, но что же с ним можно делать? Прежде всего, из него можно извлекать данные, как из объектной таблицы. Например, в SQL*Plus запрос:

SQL> SELECT image_id, keywords FROM images_v;

вернет следующие данные:

MAGE_ID KEYWORDS
---------- -------------------------------------------------------
    100003 KEYWORD_TAB_T()
    100001 KEYWORD_TAB_T('HAPPY FACE', 'SIXTIES')
    100002 KEYWORD_TAB_T('JERRY RUBIN', 'PEACE SYMBOL', 'SIXTIES')

Чтобы все это еще более походило на объекты, можно добавить в определение типа методы, в частности метод print():

ALTER TYPE image_t
   ADD MEMBER FUNCTION print RETURN VARCHAR2
   CASCADE;

CREATE OR REPLACE TYPE BODY image_t
AS
   MEMBER FUNCTION print
      RETURN VARCHAR2
   IS
      filename images.file_name%TYPE;
      dirname VARCHAR2(30);
      keyword_list VARCHAR2(32767);
   BEGIN
      DBMS_LOB.FILEGETNAME(SELF.image_file, dirname, filename);
      IF SELF.keywords IS NOT NULL
      THEN
         FOR key_elt IN 1..SELF.keywords.COUNT
         LOOP
            keyword_list := keyword_list || ', ' || SELF.keywords(key_elt);
         END LOOP;
      END IF;
      RETURN 'Id=' || SELF.image_id || '; File=' || filename
         || '; keywords=' || SUBSTR(keyword_list, 3);
   END;
END;

Этот пример показывает, как сформировать «плоский» список ключевых слов, содер­жащихся в виртуальной коллекции.

Еще некоторые полезные возможности объектных представлений:

  • Использование виртуальных REF-ссылок — указатели на виртуальные объекты, подробно рассматриваются в разделе «Различия между объектными представлени­ями и объектными таблицами» (см. далее).
  • Написание триггеров INSTEAD OF с возможностью выполнения прямых операций с содержимым представления. Дополнительная информация по этой теме приведена в разделе «Триггеры INSTEAD OF» (см. далее).

NULL или нет?

NULL-коллекция — не то же самое, что инициализированная коллекция с нулем эле­ментов. Изображение 100003 не имеет ключевых слов, но объектное представление ошибочно возвращает пустую, но инициализированную коллекцию. Чтобы получить «настоящее» значение NULL, можно воспользоваться функцией DECODE для про­верки числа ключевых слов:

CREATE OR REPLACE VIEW images_v
   OF image_t
   WITH OBJECT IDENTIFIER (image_id)
AS
   SELECT i.image_id, BFILENAME('ROOTDIR', i.file_name),
          i.file_type, i.bytes,
          DECODE((SELECT COUNT(*)
                    FROM keywords k2
                  WHERE k2.image_id = i.image_id),
               0, NULL,
               CAST (MULTISET (SELECT keyword
                                 FROM keywords k
                              WHERE k.image_id = i.image_id)
                 AS keyword_tab_t))
   FROM images i;

Иначе говоря, при отсутствии ключевых слов возвращается NULL; в остальных слу­чаях возвращается выражение CAST/MULTISET. С этим представлением команда SELECT...WHERE image_id=100003 дает следующий результат:

  IMAGE_ID KEYWORDS
---------- -------------------------------------------------------
    100003

Пожалуй, эта концептуальная чистота не стоит лишних операций ввода/вывода (или необходимости разбираться в запутанной команде SELECT).

 

Объектные подпредставления (Object Subview)

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

CREATE TYPE supplier_t AS OBJECT (
   id INTEGER,
   name VARCHAR2(400)
);

Соответствующее объектное представление выглядит так:

CREATE VIEW suppliers_v
   OF supplier_t
   WITH OBJECT IDENTIFIER (id)
AS
   SELECT id, name
     FROM suppliers;

Теперь изменим или удалим и повторно создадим базовый тип, но уже с секцией NOT FINAL:

ALTER TYPE image_t NOT FINAL CASCADE;

чтобы затем создать для него подтип:

CREATE TYPE supplied_images_t UNDER image_t (
   supplier_ref REF supplier_t,
   supplier_rights_descriptor VARCHAR2(256)
);

Завершив подготовку, мы создаем представление на основе подтипа и включаем в его определение предложение UNDER:

CREATE VIEW supplied_images_v
        OF supplied_images_t                UNDER images_v
AS
   SELECT i.image_id, BFILENAME('ROOTDIR', i.file_name),
          i.file_type, i.bytes,
          CAST (MULTISET (SELECT keyword
                            FROM keywords k
                           WHERE k.image_id = i.image_id)
            AS keyword_tab_t),
          MAKE_REF(suppliers_v, supplier_id),
          supplier_rights_descriptor
     FROM images i
    WHERE supplier_id IS NOT NULL;

Oracle не позволяет при формировании подпредставления запрашивать данные из су­перпредставления, поэтому в данном случае мы обращаемся непосредственно к базовой таблице, а условие WHERE ограничивает набор извлекаемых записей. Также обратите внимание на то, что в подпредставлениях не используется секция WITH OBJECT IDENTIFIER, поскольку они наследуют идентификаторы объектов от суперпредставления.

В этом запросе используется новая функция MAKE_REF, предназначенная для вычисления ссылки на виртуальный объект. В данном случае он представляет поставщика, возвра­щаемого представлением suppliers_v. Синтаксис функции MAKE_REF:

FUNCTION MAKE_REF (представление, список_значений) RETURN ссылка;

Здесь представление — это объектное представление, на которое должна указывать ссыл­ка, заданная в значении аргумента ссылка, а список_значений — разделенный запятыми список значений столбцов, типы данных которых должны в точности соответствовать типам данных OID-атрибутов представления.

Учтите, что функция MAKE_REF всего лишь применяет встроенный алгоритм Oracle для построения REF-значения. Однако, как и REF-ссылки, виртуальные ссылки могут не указывать на реальные объекты.

А теперь неожиданный результат — хотя мы не изменяли суперпредставление, изобра­жения от поставщиков теперь выводятся им дважды (то есть дублируются):

SQL> SELECT COUNT(*), image_id FROM images_v GROUP BY image_id;

  COUNT(*)   IMAGE_ID
---------- ----------
         2     100001
         2     100002
         1     100003

Oracle возвращает логическое объединение (UNION ALL) двух запросов: к суперпредстав­лению и подпредставлению. И в этом есть смысл, ведь изображение от поставщика не перестает быть изображением. Для удаления дубликатов включите в родительское пред­ставление условие WHERE, которое исключает строки, возвращаемые в подпредставлении:

CREATE OR REPLACE VIEW images_v AS
   ...
   WHERE supplier_id IS NULL;

 

Объектное представление с обратным отношением (Inverse Relationship)

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

CREATE TYPE image_refs_t AS TABLE OF REF image_t;

CREATE TYPE keyword_t AS OBJECT (
   keyword VARCHAR2(45),
   image_refs image_refs_t);

Определение представления выглядит так:

CREATE OR REPLACE VIEW keywords_v
   OF keyword_t
   WITH OBJECT IDENTIFIER (keyword)
AS
   SELECT keyword, CAST(MULTISET(SELECT MAKE_REF(images_v, image_id)
                                   FROM keywords
                                  WHERE keyword = main.keyword)
                     AS image_refs_t)
     FROM (SELECT DISTINCT keyword FROM keywords) main;

Запросы к данному представлению не будут отличаться быстротой; ведь при этом нужно выполнять операцию SELECT DISTINCT, так как в базе данных нет справочной таблицы ключевых слов. Даже без использования объектных функций с точки зрения времени эти запросы обходились бы дорого.

Вы можете справедливо заметить, что использование MAKE_REF не обязательно; для получения REF также можно воспользоваться внутренним запросом к images_v (вместо таблицы keywords). В общем случае MAKE_REF работает быстрее, чем поиск по объектному представлению, а в некоторых ситуациях такой поиск вообще невозможен.

Как бы то ни было, на этой стадии я могу выполнять запросы типа следующего:

SQL> SELECT DEREF(VALUE(i)).print()
  2    FROM keywords_v v, TABLE(v.image_refs) i
  3   WHERE keyword = 'SIXTIES';

DEREF(VALUE(I)).PRINT()
------------------------------------------------------------------------------------
Id=100001; File=/files/web/60s/smiley_face.gif; keywords=HAPPY FACE, SIXTIES
Id=100002; File=/files/web/60s/peace_symbol.gif; keywords=JERRY RUBIN, PEACE,
SIXTIES

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

 

Триггеры INSTEAD OF

Синтаксис триггеров INSTEAD OF был описан здесь, и в этом разделе он не рассма­тривается. Мы обсудим только применение этих триггеров для обновления объектных представлений. Если вы намерены освоить объектный подход, вас может заинтересовать, не являются ли триггеры INSTEAD OF просто реляционным дополнением, позволяющим приложениям выполнять DML-операции. Рассмотрев аргументы «за» и «против», вы сможете решить, какой подход лучше выбрать для своего приложения.

аргументы «против»

Для инкапсуляции DML-операций гораздо лучше триггеров INSTEAD OF подходят пакеты и объектные методы PL/SQL. Логика такого триггера легко переносится в альтернативную конструкцию PL/SQL, имеющую более универсальное применение. Иначе говоря, если для выполнения DML в системе используется давно стандарти­зированный и отлаженный механизм пакетов и методов, то эти триггеры в него могут совершенно не вписаться и лишь усложнят вашу работу.

Более того, даже Oracle предупреждает, что триггерами не стоит злоупотреблять, потому что они могут создавать сложные взаимозависимости. Если триггер INSTEAD OF выпол­няет DML-инструкцию для таблиц, у которых имеются другие триггеры, выполняющие DML-инструкции для других таблиц с триггерами, то... как вы это все будете отлаживать?

аргументы «за»

Значительную часть логики, обычно реализуемой в пакете или теле метода, можно перенести в триггер INSTEAD OF. В сочетании с продуманным набором привилегий это позволит защитить данные лучше, чем с помощью методов и пакетов.

Если вы пользуетесь таким клиентским средством, как Oracle Forms, то при создании в форме «блока» на основе представления, а не таблицы триггеры позволяют применять гораздо больше встроенных возможностей этого продукта.

При использовании OCI, когда объектное представление не подлежит модификации, а кэшируемые данные объектного представления нужно быстро отправлять обратно на сервер, триггеры INSTEAD OF просто необходимы.

главный вопрос

Куда следует помещать команды, выполняющие вставку, обновление и удаление данных, особенно при использовании объектных представлений? Если вы хотите локализовать эти операции на сервере, имеются как минимум три варианта: пакеты PL/SQL, объ­ектные методы и триггеры INSTEAD OF.

В табл. 1 приведены сравнительные характеристики этих вариантов. Заметьте, что мы рассматриваем их исключительно с точки зрения размещения DML-операций над объектными представлениями.

Таблица 1. Сравнение способов инкапсуляции DML-операций над объектными представлениями

Характеристика

Пакет PL/SQL

Объектный метод

Триггер INSTEAD OF

Соответствие объект­но-ориентированному подходу

Потенциально очень хорошее

Прекрасное

Потенциально очень хорошее

Возможность модифи­кации при изменении схемы

Имеется, код легко моди­фицировать и независимо перекомпилировать

Имеется (в Oracle9i)

Имеется

Риск непредвиденных последствий

Низкий

Низкий

Высокий; триггеры могут иметь скрытые зависимости

Взаимодействие со стандартными функци­ями клиентских средств (в частности, Oracle Developer)

Программист должен добавить код для всех клиентских транзакцион­ных триггеров

Программист должен добавить код для всех клиентских транзакционных триг­геров

Хорошо реализуется для типов верхнего уровня (однако не существует серверного триггера

INSTEAD OF LOCK)

Возможность включать­ся и отключаться по желанию

Отсутствует

Отсутствует

Имеется (путем от­ключения и включения триггера)

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

 

У триггеров INSTEAD OF в иерархии представлений есть одна важная особенность: для каждого уровня иерархии необходимо создавать отдельный триггер. При выполнении команды DML применительно к подпредставлению запускается триггер подпредстав­ления, а применительно к суперпредставлению — триггер суперпредставления.

Триггеры INSTEAD OF могут использоваться в сочетании с пакетами PL/SQL и/или объ­ектными методами для обеспечения многоуровневой инкапсуляции. Например:

TRIGGER images_v_insert
INSTEAD OF INSERT ON images_v
FOR EACH ROW
BEGIN
   /* Call a packaged procedure to perform the insert. */
   manage_image.create_one(:NEW.image_id, :NEW.file_type,
      :NEW.file_name, :NEW.bytes, :NEW.keywords);
END;

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

 

Различия между объектными представлениями и объектными таблицами

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

  • уникальность OID-идентификаторов;
  • возможность хранения в базе данных REF-ссылок;
  • REF-ссылки на неуникальные OID-идентификаторы.

Давайте рассмотрим каждое из перечисленных различий.

Уникальность OID-идентификаторов

Объектная таблица всегда содержит уникальный идентификатор объекта (генериру­емый системой или производный от первичного ключа). Технически возможно (хотя и нежелательно) создать объектную таблицу с дублирующимися строками, но экзем­пляры объектов в таблице все равно будут иметь уникальные идентификаторы. Данную операцию можно выполнить двумя способами:

  • Дублирование OID в одном представлении. Объектное представление может со­держать несколько экземпляров объектов (строк) с одинаковыми значениями OID. Вы уже видели пример суперпредставления с дубликатами объектов.
  • Дублирование OID в нескольких представлениях. Если объектное представление создано на основе объектной таблицы или представления и OID определяется с по­мощью ключевого слова DEFAULT, представление содержит идентификаторы объек­тов, соответствующие идентификаторам базовой структуры.

Скорее всего, вам подойдет второй способ, поскольку отдельные представления — это, по сути, сохраненные результаты запросов.

Хранение в базе данных REF-ссылок

Если вы разрабатываете приложение с «физическими» объектными таблицами, REF- ссылки на объекты могут храниться в других таблицах; в конце концов, REF — это дво­ичное значение, которое используется Oracle в качестве указателя на объект.

Но при попытке сохранения виртуальной ссылки (то есть ссылки на строку объектного представления) в реальной таблице Oracle выдаст ошибку. Поскольку виртуальная ссылка зависит от значений столбцов, вместо нее нужно сохранять эти значения. Это скорее неудобство, чем серьезное ограничение, и все же жаль, что объектные таблицы нельзя совмещать с объектными представлениями или преобразовывать их в объектные таблицы. Было бы хорошо иметь возможность создать объектную таблицу:

CREATE TABLE images2 OF image_t
   NESTED TABLE keywords STORE AS keyword_tab;

и затем заполнить ее данными из представления:

INSERT INTO images2       /* invalid because images_v includes a REF */
 SELECT VALUE(i) FROM images_v i;

К сожалению, Oracle выдает ошибку "ORA-22979: cannot INSERT object view REF or user-defined REF", однако в будущем все может измениться.

ссылки на неуникальные OID

Вряд ли возможна стабильная работа программы, содержащей ссылки на неуникальный OID при работе с объектными таблицами. Что произойдет в результате создания ссылки на объект объектного представления, содержащего несколько объектов с одинаковыми OID? Такая ситуация является аномальной; не стоит создавать представления с дубли­рующимися OID.

Наши эксперименты показали, что вызов функции DEREF для такой виртуальной ссылки возвращает объект — вероятно, первый из найденных Oracle.

Теперь поговорим о сопровождении объектных представлений и типов.

Вас заинтересует / Intresting for you:

Oracle и Java: использование P...
Oracle и Java: использование P... 1981 просмотров sepia Tue, 08 May 2018, 08:52:34
Oracle IDE: JDeveloper, SQL De...
Oracle IDE: JDeveloper, SQL De... 2165 просмотров Ольга Потемкина Tue, 21 Nov 2017, 13:18:46
Сопровождение объектных типов ...
Сопровождение объектных типов ... 240 просмотров Максим Николенко Sun, 03 Nov 2019, 09:18:04
Значения NULL в PL/SQL Oracle
Значения NULL в PL/SQL Oracle 2125 просмотров Дэн Tue, 21 Nov 2017, 13:28:01