web-dev-qa-db-fra.com

création de vues paramétrées dans Oracle11g

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
13
pri_dev

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.

15
Jeffrey Kemp

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 ...

7
Neco

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;
4
John Doyle