создание параметризованных представлений в oracle11g - PullRequest
13 голосов
/ 27 января 2012

У меня большой запрос с вложением и левым соединением и Ineed, чтобы создать из него представление, чтобы не запускать его из приложения. Проблема в том, что мне нужен диапазон дат и некоторые другие поля в качестве входных параметров, поскольку он будет отличаться от внешнего интерфейса для каждого запроса. Я только что посмотрел и увидел несколько постов, в которых говорится об использовании SYS_CONTEXT для параметризованных представлений, и мне нужно точно знать, как создать представление, например, с 2 параметрами - fromdate, todate и как я вызываю представление из приложения.

Просто для информации я использую grails / groovy для разработки приложения. и вот запрос, который я хочу создать представление из ..

 select 
    d.dateInRange as dateval,
    eventdesc,
    nvl(td.dist_ucnt, 0) as dist_ucnt
from (
    select 
        to_date(fromdate,'dd-mon-yyyy') + rownum - 1 as dateInRange
    from all_objects
    where rownum <= to_date(fromdate,'dd-mon-yyyy') - to_date(todate,'dd-mon-yyyy') + 1
) d
left join (
    select 
        to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate,
        count(distinct(grauser_id)) as dist_ucnt,
        eventdesc 
    from
        gratransaction, user_transaction 
  where gratransaction.id = user_transaction.trans_id and 
  user_transaction.transdate between to_date(fromdate,'dd-mon-yyyy') and to_date(todate,'dd-mon-yyyy') 
    group by  to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
) td on td.currentdate = d.dateInRange order by d.dateInRange asc

Ответы [ 3 ]

15 голосов
/ 27 января 2012

Метод контекста описан здесь: http://docs.oracle.com/cd/B28359_01/network.111/b28531/app_context.htm

например. (пример адаптирован из вышеуказанной ссылки)

CREATE CONTEXT dates_ctx USING set_dates_ctx_pkg;

CREATE OR REPLACE PACKAGE set_dates_ctx_pkg IS 
  PROCEDURE set(d1 in date, d2 in date); 
END; 
/

CREATE OR REPLACE PACKAGE BODY set_dates_ctx_pkg IS
  PROCEDURE set(d1 in date, d2 in date) IS 
  BEGIN 
    DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd1', TO_CHAR(d1,'DD-MON-YYYY'));
    DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd2', TO_CHAR(d2,'DD-MON-YYYY'));
  END;
END;
/

Затем установите даты в вашем приложении с помощью:

BEGIN set_dates_ctx_pkg.set(mydate1, mydate2); END;
/

Затем запросите параметры с помощью:

SELECT bla FROM mytable
WHERE mydate
  BETWEEN TO_DATE(
            SYS_CONTEXT('dates_ctx', 'd1')
          ,'DD-MON-YYYY')
      AND TO_DATE(
            SYS_CONTEXT('dates_ctx', 'd2')
          ,'DD-MON-YYYY');

Преимущество этого подхода в том, что он очень удобен для запросов; он не использует DDL или DML во время выполнения и, следовательно, не нужно беспокоиться о транзакциях; и это очень быстро, потому что не требует переключения контекста SQL - PL / SQL.

С другой стороны:

Если метод контекста и метод переменных пакета Джона для вас невозможны, другой способ - вставить параметры в таблицу (например, глобальную временную таблицу, если вы выполняете запрос в том же сеансе), затем присоединитесь на эту таблицу с точки зрения. Недостатком является то, что теперь вам нужно убедиться, что вы запускаете DML для вставки параметров всякий раз, когда вы хотите выполнить запрос.

6 голосов
/ 30 декабря 2014

Я только что обошел этот досадный недостаток Oracle.Например,

create or replace package pkg_utl
as
  type test_record is record (field1 number, field2 number, ret_prm_date date);
  type test_table is table of test_record;
  function get_test_table(prm_date date) return test_table pipelined;
end;
/

create or replace package body pkg_utl
as
  function get_test_table(prm_date date) return test_table pipelined
  is
  begin
    for item in (
      select 1, 2, prm_date
      from dual
    ) loop
      pipe row (item);
    end loop;
    return;
  end get_test_table;
end;
/

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

select *
from table(pkg_utl.get_test_table(sysdate))

Я не уверен в производительности ...

4 голосов
/ 27 января 2012

Для использования параметров в представлении одним из способов является создание пакета, который будет устанавливать значения ваших параметров и иметь функции, которые можно вызывать для получения этих значений. Например:

create or replace package MYVIEW_PKG as
  procedure SET_VALUES(FROMDATE date, TODATE date);

  function GET_FROMDATE
    return date;

  function GET_TODATE
    return date;
end MYVIEW_PKG;

create or replace package body MYVIEW_PKG as
  G_FROM_DATE   date;
  G_TO_DATE     date;

  procedure SET_VALUES(P_FROMDATE date, P_TODATE date) as
  begin
    G_FROM_DATE := P_FROMDATE;
    G_TO_DATE := P_TODATE;
  end;

  function GET_FROMDATE
    return date is
  begin
    return G_FROM_DATE;
  end;

  function GET_TODATE
    return date is
  begin
    return G_TO_DATE;
  end;
end MYVIEW_PKG;

Тогда ваш вид может быть создан таким образом:

create or replace view myview as
    select 
        d.dateInRange as dateval,
        eventdesc,
        nvl(td.dist_ucnt, 0) as dist_ucnt
    from (
        select 
            MYVIEW_PKG.GET_FROMDATE + rownum - 1 as dateInRange
        from all_objects
        where rownum <= MYVIEW_PKG.GET_FROMDATE - MYVIEW_PKG.GET_TODATE + 1
    ) d
    left join (
        select 
            to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate,
            count(distinct(grauser_id)) as dist_ucnt,
            eventdesc 
        from
            gratransaction, user_transaction 
      where gratransaction.id = user_transaction.trans_id and 
      user_transaction.transdate between MYVIEW_PKG.GET_FROMDATE and MYVIEW_PKG.GET_TODATE
        group by  to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
    ) td on td.currentdate = d.dateInRange order by d.dateInRange asc;

И чтобы запустить его, сначала нужно установить значения:

exec MYVIEW_PKG.SET_VALUES(trunc(sysdate)-1,trunc(sysdate));

И тогда вызовы к нему будут использовать эти значения:

select * from myview;
...