GPO ( Grupo de Profissionais Oracle )
A maior comunidade Oracle do Brasil !

Views no RDBMS Oracle : O que são, como funcionam e um método para se obter uma View parametrizável

Views no RDBMS Oracle

Um recurso muito simples em tese no SGBD Oracle (e que existe em muitos outros SGBDs) são as views : no Oracle porém quando você cria uma view não há uma sintaxe para se passar Parâmetros em tempo de runtime para ela (ao contrário de uma função, por exemplo), e como recentemente tive essa necessidade, vou ilustrar aqui essa técnica, e aproveitarei também para conceituar melhor as views…

O que são as views : falando das views SIMPLES (que criamos com CREATE VIEW, views Materializadas, Snapshots e Updateable views são animaizinhos diferentes),  ao fim e ao cabo uma view NADA MAIS É do que um SELECT , uma query, cujo texto fica Armazenado no database e quando necessário é lido e executado, nada mais… Ainda é possível se encontrar livros ruins e sites piores ainda que sugerem que a view funcionaria como uma cópia dos dados (ie, os dados lidos pela view seriam ‘copiados’ para outro local do disco, de alguma maneira), o que é uma simples falácia, não é nem de longe assim que uma view simples funciona… Vamos a um exemplo: Digamos que tenho uma tabela EMP (que contém os Empregados da Empresa), com a seguinte estrutura

scott@DESENV:SQL>desc emp
  Nome                                      Nulo?    Tipo
 ------------------------------------------ -------- -------------
 EMPNO                                     NOT NULL NUMBER(4)
  ENAME                                              VARCHAR2(10)
  JOB                                                VARCHAR2(9)
  MGR                                                NUMBER(4)
  HIREDATE                                           DATE
  SAL                                                NUMBER(7,2)
  COMM                                               NUMBER(7,2)
  DEPTNO                                             NUMBER(2)

E desejo criar uma view que só mostre os Empregados do departamento 10, eu criaria a view assim (vou colocar o texto do SELECT da view em amarelo apenas para o destacar):

scott@DESENV:SQL> create view V_EMPS_DEPTO_10 as select empno, ename, sal from emp where deptno = 10;
 View criada.

Pronto, a partir desse momento em qualquer SQL onde eu referencie esse objeto V_EMPS_DEPTO_10 essa referência VAI ser substituída pelo SELECT da view.. Por exemplo, se eu escrever:

SELECT * FROM V_EMPS_DEPTO_10;

O que o banco na verdade vai executar é:

SELECT * FROM (select empno, ename, sal from emp where deptno = 10);

Isso é muito fácil de comprovar – podia usar N outros métodos, vou usar o AUTOTRACE do sqlplus…

OBSERVAÇÃO : – num ambiente de teste/desenv essa ferramenta já deve muito provavelmente estar configurada, mas se não estiver E você queira a usar para reproduzir o exemplo , é simples : conectado como usuário SYS no sqlplus no servidor Oracle, no local onde o Oracle foi instalado(que nesta máquina de exemplo foi E:\oracle\product\10.2.0\db_1) haverá um subdiretório sqlplus e nesse subdiretório haverá ainda outro sub-diretório admin, nele está o script que cria a role necessária para usar o AUTOTRACE , basta executar o script (que nesta máquina:

SYS@DESENV:SQL> @E:\oracle\product\10.2.0\db_1\sqlplus\admin\plustrce.sql

Feito isso é so permissionar o usuário que vai usar a ferramenta, o SCOTT no meu caso:

SYS@DESENV:SQL>GRANT PLUSTRACE TO SCOTT;

Continuando, é ativado o autotrace e executada a consulta referenciando a view:

scott@DESENV:SQL>set autotrace on
scott@DESENV:SQL>select * from V_EMPS_DEPTO_10;

      EMPNO ENAME             SAL
---------- ---------- ----------
      7782 CLARK            2450
      7839 KING             5000
      7934 MILLER           1300 

Plano de Execução
----------------------------------
 Plan hash value: 3956160932

---------------------------------------------------------------------------
 | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
 |   0 | SELECT STATEMENT  |      |     3 |    51 |     3   (0)| 00:00:01 |
 |*  1 |  TABLE ACCESS FULL| EMP  |     3 |    51 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

 Predicate Information (identified by operation id):
-----------------------------------------------------
 1 - filter("DEPTNO"=10)

 Estatística
----------------------------------------------------------
        300  recursive calls
          0  db block gets
         66  consistent gets
          6  physical reads
          0  redo size
        729  bytes sent via SQL*Net to client
        488  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          8  sorts (memory)
          0  sorts (disk)
          3  rows processed 

Vou desativar o AUTOTRACE pois não precisarei mais dele:

 scott@DESENV:SQL>set autotrace off 

Veja que a tabela efetivamente lida foi a EMP, E que as colunas retornadas foram as colunas da query na EMP estabelecida na view…

Esse fato de que a query indicada na criação da view é executada como uma “sub-query”,  como uma fonte Interna de dados, leva diretamente à uma questão : se o SELECT “externo” que vai ler os dados retornado pela SELECT ‘interno’ da view tiver predicados, condições de filtro e complementos do tipo, nem sempre vai ser possível para o RDBMS “importar” esses itens externos para a sub-query ‘interna’, conforme este link mostra….

Exemplificando, digamos então que a nossa view exemplo necessite ser usada dentro dum aplicativo onde o usuário (através duma interface gráfica, certamente) popula uma variável V_DEPTNO com o número do departamento a pesquisar, não sendo mais fixo sempre depto 10 – o RDBMS Oracle não aceita ainda você ter um parâmetro na criação da view (ao contrário de outros objetos programáticos, como Procedures, Funções, etc.) mas há várias opções para se criar algo nesse sentido : a mais simples seria vc simplesmente ter uma tabela ‘de trabalho’, inicialmente vazia, onde o Aplicativo iria inserir os dados necessários e a query da view iria ler esses dados através de um operador IN ou EXISTS….

Porém, Outra possibilidade é colocar os valores desejados em Variáveis Globais, preferencialmente Independentes entre sessões, de modo que cada sessão possa ter seus valores próprios informados por cada sessão usando o aplicativo : dentro de um database gerenciado pelo RDBMS Oracle, entre os vários mecanismos que são possíveis (como CONTEXTS , Global Temporary Tables, variáveis globais definidas numa declaração de Package, etc ), um dos mais antigos e simples é chamada ao PL/SQL, com um método de GET e outro de PUT, será o usado neste exemplo…

Primeiro declaramos o conteúdo da package – vai haver uma Procedure para popular a variável interna G_DEPTNO e uma função que retorna o conteúdo:

 scott@DESENV:SQL> create or replace PACKAGE PKG_CONSULTA_DEPTOS  AS
   2     -- Procedure a ser Chamada Antes de usar a view
   3     PROCEDURE P_SET_DEPTNO (P_DEPTNO NUMBER);
   4     -- Função a ser chamada na view para Recuperar o conteúdo da variável Global packaged
   5     FUNCTION  F_GET_DEPTNO RETURN NUMBER;
   6  END;
   7* / 
 Pacote criado. 

Depois criamos o corpo da package, onde haverá o código fonte das duas rotinas declaradas E será definida e populada a variável – como a variável foi definida FORA das rotinas da package pode ser referenciada/usada em qualquer uma das rotinas dessa package… Exemplo:

 
scott@DESENV:SQL> create or replace PACKAGE BODY PKG_CONSULTA_DEPTOS  AS
   2     g_DEPTNO  NUMBER;
   3     --
   4     PROCEDURE P_SET_DEPTNO(P_DEPTNO NUMBER) is
   5     Begin
   6       g_DEPTNO := p_DEPTNO;
   7     End;
   8     --
   9     FUNCTION F_GET_DEPTNO RETURN NUMBER is
  10     Begin
  11       RETURN g_DEPTNO;
  12     End;
  13     -- Fim do Package Body
  14 END;
  15 /
  
 Corpo de Pacote criado. 

Com os objetos no lugar, eles podem ser referenciados, vou criar a view:

scott@DESENV:SQL> create view V_EMPS_DEPTOS as select deptno, empno, ename, sal from emp where deptno = PKG_CONSULTA_DEPTOS.F_GET_DEPTNO;
 View criada. 

Ok, com isto a Aplicação que vai consumir a view já pode Popular a variável e depois consultar a view – no exemplo vou usar o sqlplus como se fosse a Aplicação e chamar os métodos necessários mas Obviamente isso seria feito na Aplicação… Digamos que numa sessão 1 um usuário queira parametrizar a view para  retornar empregados do depto 10 :

 scott@DESENV:SQL#1>exec  PKG_CONSULTA_DEPTOS.P_SET_DEPTNO(10);
 scott@DESENV:SQL#1> select * from V_EMPS_DEPTOS;
  DEPTNO      EMPNO ENAME             SAL
 ---------- ---------- ---------- ----------
         10       7782 CLARK            2450
         10       7839 KING             5000
         10       7934 MILLER           1300 

E então simultaneamente outra sessão queira consultar outro depto:

 scott@DESENV:SQL#2>exec PKG_CONSULTA_DEPTOS.P_SET_DEPTNO(20);
 Procedimento PL/SQL concluído com sucesso.

 scott@DESENV:SQL#2>select * from V_EMPS_DEPTOS;
  
     DEPTNO      EMPNO ENAME             SAL
 ---------- ---------- ---------- ----------
         20       7369 SMITH             800
         20       7566 JONES            2975
         20       7788 SCOTT            3000
         20       7876 ADAMS            1100
         20       7902 FORD             3000
  
 scott@DESENV:SQL#2> 

Share

You may also like...

1 Response

  1. Daniel disse:

    muito legal, não sabia que dava para fazer assim 🙂

Deixe um comentário

O seu endereço de e-mail não será publicado.