Пример использования Oracle HTML DB (APEX)

По этой ссылке вы можете оценить приложение «Заказы клиентов», написанное на Oracle HTML DB и работающее на нашем сервере с базой данных Oracle 10g. Идентификатор пользователя - а, пароль также а на английском.

Запустить «Заказы клиентов (Версия 2)»

Oracle HTML DB - это инструмент, позволяющий быстро и без больших накладных затрат, создавать приложения с WEB - интерфейсом. Дешевизна заключается в том, что не нужно покупать сервер приложений, HTML DB или последняя версия APEX входит в комплект поставки Oracle database server 10g, сервер Apache устанавливается также по умолчанию, в нашей установке используется именно такая конструкция. Простота обеспечивается возможностями инструмента Oracle HTML DB или APEX, которые демонстрируется нашей публикацией.

     Здравствуйте, коллеги!
   Вдохновленные первым опытом работы с Oracle HTML DB (начиная с версии 2.1 имеет название Oracle Application Express, или APEX), мы стали искать пути минимизации трафика, да и уменьшения количества скрытых элементов управления, т.к. при достаточно сложном проекте передавать от страницы к странице через HIDDEN достаточно проблематично и некрасиво. Наши поиски привели к достаточно простой, но, в то же время, достаточно удобной, возможности APEX, а именно COLLECTIONS (коллекции). В данной публикации постараемся рассказать о создании и работе с коллекциями.
   Перед чтением, рекомендуем, ознакомиться с предыдущей публикацией, т.к. останавливаться на таких вещах, как добавлении элементов на страницу и создании динамических отчетов не будем. Информация по работе с коллекциями доступна в официальной документации по APEX.
   В нашем примере будем использовать 2 коллекции: SALEORDER_MAIN и SALEORDER_SUB – шапка и детали заказа, соответственно. Для создания коллекций будем использовать функцию APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION('имя коллекции') – данная функция создает, если не была создана, коллекцию или очищает коллекцию от элементов, если коллекция была создана.
   Для доступа к элементам коллекции используется представление APEX_COLLECTIONS. Представление содержит следующие поля:

     ИМЯ            ПУСТО        ТИП
_______________   ________   _____________
COLLECTION_NAME   NOT NULL   VARCHAR2(255)
SEQ_ID              NULL     NUMBER
C001                         VARCHAR2(4000)
C002                         VARCHAR2(4000)
...                             ...
C050                         VARCHAR2(4000)
CLOB001                      CLOB
MD5_ORIGINAL                 VARCHAR2(4000)


    ОТОБРАЖЕНИЕ ЗАКАЗА

   Для нашего примера примем следующее: в коллекции SALEORDER_MAIN в поле C001 содержится имя «переменной», в поле С002 – значение. В коллекции SALEORDER_SUB – каждая запись соответствует каждой записи в детали заказа, а каждый атрибут содержит атрибут данной строки заказа, например, поле С001 содержит номер кода товара, С005 количество, С003 – цену и проч. Итак, приступим, сначала опишем процесс, который заполняет информационные поля страницы: номер заказа, клиент, сумма заказа.

   Создаем процесс, который будет срабатывать ON LOAD – BEFORE HEAD, содержащий следующий PL/SQL anonymous block:

-- объявляем требуемые переменные
DECLARE
    ls_login VARCHAR2(100);
    ls_invoice VARCHAR2(100);
    ln_cnt NUMBER;
    ls_accnum VARCHAR2(100);
    ls_subaccnum VARCHAR2(100);
    ls_contractor VARCHAR2(100);
    ls_total VARCHAR2(100);
BEGIN
   -- есть ли INVOICE (подномер) у текущего заказа?
   -- Наличие подномера – условие того, что заказ записан
    SELECT COUNT(*)
    INTO ln_cnt
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'INVOICE') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');
   -- если да - прочитать
    IF ln_cnt > 0 THEN
       SELECT c002
       INTO ls_invoice
       FROM APEX_COLLECTIONS
       WHERE (UPPER(c001) = 'INVOICE') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');
    ELSE
       ls_invoice := 'нов';
    END IF;
   -- прочитать LOGIN (номер заказа)
    SELECT c002
    INTO ls_login
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'LOGIN') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');
   -- прочитать номер счета клиента
    SELECT c002
    INTO ls_accnum
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'ACCNUM') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');
   -- прочитать номер субсчета клиента
    SELECT c002
    INTO ls_subaccnum
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'SUBACCNUM') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');
   -- прочитать название контрагента
    SELECT CONTRACTOR
    INTO ls_contractor
    FROM #OWNER#.EA_ACCOUNT
    WHERE (ACCOUNT_NUM = ls_accnum) AND (SUBACCOUNT_NUM = ls_subaccnum);
   -- есть ли детали у текущего заказа?
    SELECT COUNT(*)
    INTO ln_cnt
    FROM APEX_COLLECTIONS
    WHERE (UPPER(COLLECTION_NAME) = 'SALEORDER_SUB');
    IF ln_cnt > 0 THEN
-- если есть, то просуммировать количество*цена. Т.к. поля С001, С002 … С050 – строковые, поэтому приходится помучиться со сменой «.» на «,»
      SELECT
            TO_CHAR(SUM(DECODE(INSTR(NVL(c003,'0'),'.'),0,TO_NUMBER(NVL(c003,'0')),(TO_NUMBER(SUBSTR(c003,1,INSTR(c003,'.')-1)||','||SUBSTR(c003,INSTR(c003,'.')+1))))
            *
            DECODE(INSTR(NVL(c005,'0'),'.'),0,TO_NUMBER(NVL(c005,'0')),(TO_NUMBER(SUBSTR(c005,1,INSTR(c005,'.')-1)||','||SUBSTR(c005,INSTR(c005,'.')+1))))))
       INTO ls_total
       FROM APEX_COLLECTIONS
       WHERE (COLLECTION_NAME = 'SALEORDER_SUB');
    ELSE
       ls_total := '0';
    END IF;
   -- присвоить элементам на странице полученные значения
    :P7_HEAD := ls_login||'/'||ls_invoice;
    :P7_ACC := ls_accnum||'/'||ls_subaccnum||' '||ls_contractor;
    :P7_TOTAL := ls_total;
END;

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

SELECT 'Изменить',
    APEX_COLLECTIONS.c001,
    COMMODITY.COMMODITY,
    APEX_COLLECTIONS.c002,
    APEX_COLLECTIONS.c003,
    APEX_COLLECTIONS.c004,
    APEX_COLLECTIONS.c005,
    'Рассчет цены'
FROM #OWNER#.COMMODITY, APEX_COLLECTIONS
WHERE (TO_CHAR(COMMODITY.CODE) = APEX_COLLECTIONS.c001)
ORDER BY COMMODITY.COMMODITY, APEX_COLLECTIONS.c001

   #OWNER# - это имя схемы БД, в которой мы работаем.
   Теперь разработаем алгоритм добавления элементов в заказ:
      • Пользователь выбирая группы в дереве фильтрует необходимый товар
      • Набирает товар
      • Указывает его количество

    ДОБАВЛЕНИЕ ТОВАРА


   Опишем процесс добавления товара в заказ.
   Для отображения доступного товара используется динамический отчет, запрос для которого формирует следующая функция:

DECLARE
    SQLQ varchar2(3000);
    ls_accnum varchar2(100);
    ls_subaccnum varchar2(100);
    ls_pricetype varchar2(100);
    ls_branch varchar2(100);
BEGIN
-- получим необходимые параметры
    SELECT c002
    INTO ls_accnum
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'ACCNUM') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');

    SELECT c002
    INTO ls_subaccnum
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'SUBACCNUM') AND (UPPER(COLLECTION_NAME) = 'SALEORDER_MAIN');

    SELECT c002
    INTO ls_branch
    FROM APEX_COLLECTIONS
    WHERE (UPPER(c001) = 'BRANCH') AND (UPPER(COLLECTION_NAME) = 'AUTH');

    SELECT TRADE_DEF
    INTO ls_pricetype
    FROM #OWNER#.EA_ACCOUNT
    WHERE (ACCOUNT_NUM = ls_accnum) AND (SUBACCOUNT_NUM = ls_subaccnum);

   SQLQ := 'SELECT ALL TO_CHAR(''Выбрать''),
       DECODE(NVL(a.ISIN,0), 0, 0, 1),
       COMMODITY.CODE,
       COMMODITY.COMMODITY,
       COMMODITY.TYPE1,
       COMMODITY.TYPE2,
       COMMODITY.TYPE3,
       COMMODITY.SECOND_NAME,
       SELL_PRICES.SELL_PRICE,
       SUM(NVL(REMAINS.QUANTITY,0)) ';
   -- если установлен флаг выбора товара, только того, который находится на складе, то отображать только этот товар
   IF v('P15_INSTORAGE') = '1' THEN
       SQLQ := SQLQ||'FROM COMMODITY,
          SELL_PRICES,
          REMAINS,
          STORAGE_GROUP,
          STORAGE, (SELECT COMMODITY.CODE AS CODE, COUNT(*) AS ISIN FROM APEX_COLLECTIONS, COMMODITY WHERE (TO_CHAR(COMMODITY.CODE) = APEX_COLLECTIONS.c001) AND (UPPER(COLLECTION_NAME) = ''SALEORDER_SUB'') GROUP BY COMMODITY.CODE) a
       WHERE (COMMODITY.CODE = a.CODE (+)) AND
          (REMAINS.CODE = COMMODITY.CODE) AND
          (STORAGE_GROUP.STORAGE_GROUP = STORAGE.STORAGE_GROUP) AND
          (STORAGE.STORAGE = REMAINS.STORAGE) AND
          (UPPER(STORAGE_GROUP.BRANCH) = UPPER('''||ls_branch||''')) AND
          (SELL_PRICES.CODE = REMAINS.CODE ) AND
          (UPPER(SELL_PRICES.PRICE_NAME) = UPPER('''||ls_pricetype||''')) ';
   ELSE
       SQLQ := SQLQ||'FROM COMMODITY,
          SELL_PRICES,
          REMAINS,
          (SELECT COMMODITY.CODE AS CODE, COUNT(*) AS ISIN FROM APEX_COLLECTIONS, COMMODITY WHERE (TO_CHAR(COMMODITY.CODE) = APEX_COLLECTIONS.c001) AND (UPPER(COLLECTION_NAME) = ''SALEORDER_SUB'') GROUP BY COMMODITY.CODE) a
          WHERE (COMMODITY.CODE = a.CODE (+)) AND
          (COMMODITY.CODE = REMAINS.CODE (+)) AND
          (SELL_PRICES.CODE = COMMODITY.CODE) AND
          ( SELL_PRICES.PRICE_NAME = '''||ls_pricetype||''' ) ';
   END IF;
   -- Добавим фильтры по группам товара
    SQLQ := SQLQ||' AND (UPPER(NVL(COMMODITY.TYPE1, '' '')) like UPPER('''||V('P15_TYPE1')||''')) ';
    SQLQ := SQLQ||' AND (UPPER(NVL(COMMODITY.TYPE2,'' '')) like UPPER('''||V('P15_TYPE2')||'''))';
    SQLQ := SQLQ||' AND (UPPER(NVL(COMMODITY.TYPE3,'' '')) like UPPER('''||V('P15_TYPE3')||'''))';
   SQLQ := SQLQ||'GROUP BY a.ISIN,
       COMMODITY.CODE,
       COMMODITY.TYPE1,
       COMMODITY.TYPE2,
       COMMODITY.TYPE3,
       COMMODITY.SECOND_NAME,
       COMMODITY.COMMODITY,
       SELL_PRICES.SELL_PRICE
       ORDER BY COMMODITY.COMMODITY,
          COMMODITY.CODE';
   RETURN SQLQ;
END;

   По нажатию на поле «Выбрать» переходим на данную же страницу, устанавливая элементам P15_ISADD и P15_CODE значения 1 и #COL03# (код товара) соответственно.

   Т.е. когда значение у элемента P15_ISADD становится равным 1, то срабатывает следеющий процесс (Condition type: Value of Item in Expression 1 = Expression 2, Expression 1: P15_ISADD, Expression 2: 1)

DECLARE
    ln_cnt NUMBER;
    ls_price VARCHAR2(100);
    ls_branch VARCHAR2(100);
    ls_pricesale VARCHAR2(100);
    ls_date VARCHAR2(100);
    ls_code VARCHAR2(100);
    ln_code NUMBER;
    ls_quantity VARCHAR2(100);
    ln_price NUMBER;
    ln_pricesale NUMBER;
    ln_trade_per NUMBER; -- Наценка по клиенту
    ln_type_per NUMBER; -- Наценка по товару
    ln_delay_per NUMBER; -- Наценка по отсрочке
    ld_datefrom DATE;
    ld_dateto DATE;
    ln_accnum NUMBER;
    ln_subaccnum NUMBER;
    ls_tradedef VARCHAR2(100);
    ls_curr VARCHAR2(100);
    ls_currtype VARCHAR2(100);
    ls_type1 VARCHAR2(100);
    ls_type2 VARCHAR2(100);
    ls_type3 VARCHAR2(100);
BEGIN
    SELECT BRANCH
    INTO ls_branch
    FROM OR_BRANCH
    WHERE FL_IS_LOCAL = 1;

    SELECT COUNT(*)
    INTO ln_cnt
    FROM APEX_COLLECTIONS
    WHERE collection_name = 'SALEORDER_SUB';

-- Если нет такой коллекции, то создаем
    IF ln_cnt = 0 THEN
      APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION('SALEORDER_SUB');
    END IF;

    SELECT COUNT(*)
    INTO ln_cnt
    FROM APEX_COLLECTIONS
    WHERE (collection_name = 'SALEORDER_SUB') AND (c001 = V('P15_CODE'));

-- Если есть такой товар в заказе, то сначала удалим
    IF ln_cnt <> 0 THEN
       APEX_COLLECTION.DELETE_MEMBERS( 'SALEORDER_SUB', 1, V('P15_CODE'));
    END IF;

    ls_date := TO_CHAR(sysdate());
    ls_code := V('P15_CODE');
    ln_code := TO_NUMBER(ls_code)
;     ls_quantity := V('P15_QUANTITY');
    ld_datefrom := trunc(sysdate());

// Здесь пропущены операции чтения и применения разного рода наценок
    ln_pricesale := ln_price;
    ls_price := TO_CHAR(ln_price);
    ls_pricesale := TO_CHAR(ln_pricesale);

// Добавляем нового члена
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_SUB', ls_code, ls_price, ls_pricesale, ls_date, ls_quantity );
END;


    СОХРАНЕНИЕ ЗАКАЗА

   Шапку сделали, детали добавили – теперь сохраним данный заказ, думаем, тут комментарии излишни:

DECLARE
    ln_login NUMBER;
    ln_invoice NUMBER;
    ln_cnt NUMBER;
    ln_accnum NUMBER;
    ln_subaccnum NUMBER;
    ls_branch VARCHAR2(100);
    ls_customer VARCHAR2(100);
    ls_pricename VARCHAR2(100);
    ls_billnote VARCHAR2(3000);
    ls_drivenote VARCHAR2(3000);
    ln_percents NUMBER;
    ld_date DATE;
    ldt_datetime DATE;
    ln_total NUMBER;
    ld_saledate DATE;
BEGIN
    SELECT c002
    INTO ls_billnote
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'BILL_NOTE');

    SELECT c002
    INTO ls_drivenote
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'DRIVE_NOTE');

    SELECT TO_NUMBER(c002)
    INTO ln_login
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'LOGIN');

    SELECT COUNT(*)
    INTO ln_cnt
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'INVOICE');

    IF ln_cnt > 0 THEN
       SELECT TO_NUMBER(c002)
       INTO ln_invoice
       FROM APEX_COLLECTIONS
       WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'INVOICE');
    ELSE
       SELECT INVOICE
       INTO ln_invoice
       FROM ID
       WHERE (LOGIN = ln_login);

       UPDATE ID SET INVOICE = INVOICE + 1
          WHERE (LOGIN = ln_login);
    END IF;

    SELECT TO_NUMBER(c002)
    INTO ln_accnum
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'ACCNUM');

    SELECT TO_NUMBER(c002)
    INTO ln_subaccnum
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'SUBACCNUM');

    SELECT c002
    INTO ls_branch
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'AUTH') AND (c001 = 'BRANCH');

    SELECT CONTRACTOR, TRADE_DEF, TRADE_PERCENT
    INTO ls_customer, ls_pricename, ln_percents
    FROM EA_ACCOUNT
    WHERE (ACCOUNT_NUM = ln_accnum) AND (SUBACCOUNT_NUM = ln_subaccnum);

    SELECT TRUNC(SYSDATE), SYSDATE
    INTO ld_date, ldt_datetime
    FROM DUAL;

    SELECT
       SUM(
      DECODE(INSTR(NVL(c003,'0'),'.'),0,TO_NUMBER(NVL(c003,'0')),(TO_NUMBER(SUBSTR(c003,1,INSTR(c003,'.')-1)||','||SUBSTR(c003,INSTR(c003,'.')+1))))
      *
      DECODE(INSTR(NVL(c005,'0'),'.'),0,TO_NUMBER(NVL(c005,'0')),(TO_NUMBER(SUBSTR(c005,1,INSTR(c005,'.')-1)||','||SUBSTR(c005,INSTR(c005,'.')+1)))))
    INTO ln_total
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_SUB');

    SELECT TRUNC(TO_DATE(c002))
    INTO ld_saledate
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_MAIN') AND (c001 = 'SALE_DATE');

    SELECT COUNT(*)
    INTO ln_cnt
    FROM SALEORDER
    WHERE (LOGIN = ln_login) AND (INVOICE = ln_invoice);

    IF ln_cnt > 0 THEN
       UPDATE SALEORDER SET TOTAL = ln_total WHERE (LOGIN = ln_login) AND (INVOICE = ln_invoice);
       DELETE FROM SALEORDER_SUB WHERE (LOGIN = ln_login) AND (INVOICE = ln_invoice);
    ELSE
       INSERT INTO SALEORDER ("LOGIN", "INVOICE", "CASH_ACC_NUM", "CASH_SUB_ACC_NUM", "BRANCH", "CUSTOMER", "PRICE_NAME", "PERCENTS", "OP_DATE", "OP_DATETIME", "SALEORDER"."TOTAL", "SALE_DATE", "CLOSED_SIGN", "ACCEPT_SIGN", "ORDER_PRIORITY", "BILL_NOTE", "DRIVE_NOTE")
          VALUES (ln_login, ln_invoice, ln_accnum, ln_subaccnum, ls_branch, ls_customer, ls_pricename, ln_percents, ld_date, ldt_datetime, ln_total, ld_saledate, 0, 0, 1, ls_billnote, ls_drivenote);
    END IF;
    INSERT INTO SALEORDER_SUB ("LOGIN", "INVOICE", "CODE", "PRICE", "PRICESALE", "DATE_SUB", "QUANTITY", "COMMENT" )
    SELECT ln_login, ln_invoice, TO_NUMBER(c001), TO_NUMBER(NVL(c002,'0')), TO_NUMBER(NVL(c003,'0')), TO_DATE(c004), TO_NUMBER(NVL(c005,'0')), c006
    FROM APEX_COLLECTIONS
    WHERE (COLLECTION_NAME = 'SALEORDER_SUB');
    COMMIT;
END;



    ЧТЕНИЕ ЗАКАЗА

   Вот, собственно, заказ и готов. Можно лишь заметить, что для чтения заказа используется следующая функция:

DECLARE
    ls_login VARCHAR2(100);
    ls_invoice VARCHAR2(100);
    ls_accnum VARCHAR2(100);
    ls_subaccnum VARCHAR2(100);
    ls_billnote VARCHAR2(100);
    ls_drivenote VARCHAR2(100);
    ls_saledate VARCHAR2(100);
    ls_sql VARCHAR2(3000);
BEGIN
   -- получим идентификатор заказа
    ls_login := V('P3_LOGIN');
    ls_invoice := V('P3_INVOICE');
    SELECT TO_CHAR(CASH_ACC_NUM), TO_CHAR(CASH_SUB_ACC_NUM), TO_CHAR(BILL_NOTE), TO_CHAR(DRIVE_NOTE), TO_CHAR(SALE_DATE)
       INTO ls_accnum, ls_subaccnum, ls_billnote, ls_drivenote, ls_saledate
       FROM SALEORDER
       WHERE(TO_CHAR(LOGIN) = ls_login) AND (TO_CHAR(INVOICE) = ls_invoice);
   -- установим значения элементов в странице
    APEX_UTIL.SET_SESSION_STATE('P3_CASH_SUB_ACC_NUM',ls_subaccnum);
    APEX_UTIL.SET_SESSION_STATE('P3_SALE_DATE',ls_saledate);
    APEX_UTIL.SET_SESSION_STATE('P3_BILL_NOTE',ls_billnote);
    APEX_UTIL.SET_SESSION_STATE('P3_DRIVE_NOTE',ls_drivenote);
   -- установим добавим элементы в коллекции
    APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION('SALEORDER_MAIN');
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','LOGIN',ls_login);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','INVOICE',ls_invoice);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','ACCNUM',ls_accnum);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','SUBACCNUM', ls_subaccnum);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','BILL_NOTE', ls_billnote);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','DRIVE_NOTE', ls_drivenote);
    APEX_COLLECTION.ADD_MEMBER('SALEORDER_MAIN','SALE_DATE', ls_saledate);
   -- заполним коллекцию из запроса
    ls_sql := 'SELECT TO_CHAR(CODE), TO_CHAR(PRICE), TO_CHAR(PRICESALE), TO_CHAR(DATE_SUB), TO_CHAR(QUANTITY), "COMMENT"
       FROM SALEORDER_SUB
       WHERE (LOGIN = '||ls_login||') AND (INVOICE = '||ls_invoice||')';
    APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION('SALEORDER_SUB');
    APEX_COLLECTION.DELETE_COLLECTION('SALEORDER_SUB');
    APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY( 'SALEORDER_SUB',ls_sql);
END;

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

  Спасибо за внимание!
   И следите за публикациями на сайте www.azsoft.ru!
   C уважением,
   группа разработчиков.

 

Вернуться

На страницу для программистов >>>       На главную >>>

Реклама: 

©Copyright 2011 АЗСофт (AZSoft)

 

  

 Powered by AZSoft
Rambler's Top100
 Copyright AZSoft.All Rights Reserved.