J'ai une grosse requête avec l'imbrication et la jointure gauche et je dois en créer une vue pour ne pas l'exécuter à partir de l'application. Le problème est que j'ai besoin de la plage de dates et de certains autres champs comme paramètres d'entrée, car cela variera par rapport à l'extrémité avant pour chaque demande. Je viens de regarder et j'ai vu quelques articles faisant référence à l'utilisation de SYS_CONTEXT pour les vues paramétrées et j'ai besoin de savoir exactement comment créer la vue par exemple avec 2 paramètres - fromdate, todate
et comment j'appelle la vue depuis l'application.
Juste pour info j'utilise grails/groovy pour développer l'application. et voici la requête que je veux créer à partir de ..
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
La méthode de contexte est décrite ici: http://docs.Oracle.com/cd/B28359_01/network.111/b28531/app_context.htm
par exemple. (exemple adapté du lien ci-dessus)
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;
/
Ensuite, définissez les dates dans votre candidature avec:
BEGIN set_dates_ctx_pkg.set(mydate1, mydate2); END;
/
Ensuite, interrogez les paramètres avec:
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');
L'avantage de cette approche est qu'elle est très conviviale pour les requêtes; il n'implique aucun DDL ou DML au moment de l'exécution, et donc il n'y a aucune transaction à craindre; et il est très rapide car il n'implique aucun changement de contexte SQL - PL/SQL.
Alternativement:
Si la méthode de contexte et la méthode des variables de package de John ne vous sont pas possibles, une autre consiste à insérer les paramètres dans une table (par exemple une table temporaire globale, si vous exécutez la requête dans la même session), puis joignez-vous à cette table de la vue. L'inconvénient est que vous devez maintenant vous assurer que vous exécutez du DML pour insérer les paramètres chaque fois que vous souhaitez exécuter la requête.
Je viens de contourner ce désagréable inconvénient Oracle. Comme ça
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;
/
il nécessite toujours un paquet, mais au moins je peux l'utiliser de manière plus pratique:
select *
from table(pkg_utl.get_test_table(sysdate))
je ne suis pas sûr de la performance ...
Pour utiliser des paramètres dans une vue, vous pouvez créer un package qui définira les valeurs de vos paramètres et aura des fonctions qui peuvent être appelées pour obtenir ces valeurs. Par exemple:
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;
Ensuite, votre vue peut être créée ainsi:
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;
Et pour l'exécuter, vous devez d'abord définir les valeurs:
exec MYVIEW_PKG.SET_VALUES(trunc(sysdate)-1,trunc(sysdate));
Et puis les appels à elle utiliseront ces valeurs:
select * from myview;