Создание параметризованных представлений в oracle11g
У меня есть большой запрос с вложением и левым соединением и Ineed, чтобы создать представление из него, чтобы не запускать его из приложения. Проблема в том, что мне нужен диапазон дат и некоторые другие поля в качестве входных параметров, так как он будет отличаться от переднего конца для каждого запроса.
Я просто посмотрел и увидел несколько сообщений, ссылающихся на использование SYS_CONTEXT для параметризованных представлений и должен точно знать, как создать представление, например, с двумя параметрами - 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
Ответы
Ответ 1
Ниже описывается метод контекста: 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.
В качестве альтернативы:
Если метод контекста и метод переменных пакета John невозможны для вас, другой должен вставить параметры в таблицу (например, глобальную временную таблицу, если вы выполняете запрос в том же сеансе), затем присоедините к этой таблице с точки зрения. Недостатком является то, что теперь вам нужно убедиться, что вы запустите некоторый DML для вставки параметров всякий раз, когда вы хотите запустить запрос.
Ответ 2
Я только что сделал обходной путь для этого неприятного недостатка 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))
Я не уверен в производительности...
Ответ 3
Для использования параметров в представлении один из способов - создать пакет, который будет устанавливать значения ваших параметров и иметь функции, которые можно вызвать для получения этих значений. Например:
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;