*/
Mostrando postagens com marcador Oracle. Mostrar todas as postagens
Mostrando postagens com marcador Oracle. Mostrar todas as postagens

quinta-feira, 2 de abril de 2015

Ultimo Dia Util Considerando Feriados em Oracle PL/SQL

/* Geralmente é complicado obter o ultimo dia válido considerando os feriados nacionais,
muito usado no ramo financeiro. */

/* Esse artigo pretende dá uma opção de como obter o ultimo dia util dentre várias soluções
encontradas na net, com o uso de stores functions do Oracle PL/SQL */

/* Mostrando como criar uma função SQL Oracle isto é em PL/SQL para obter o ultimo dia útil, considerando os feriados nacionais dentre outros assuntos correlacionados. */

/* Primeiro criamos uma tabela feriado para melhor elucidar as store functions, conforme script abaixo: */


-- DROP TABLE FERIADO;
CREATE TABLE FERIADO
(
   ID_FERIADO                       NUMBER(10,0)       NOT NULL ENABLE
 , DATA                             DATE               NOT NULL ENABLE
 , DESCRICAO                        VARCHAR2(50 BYTE)  NOT NULL ENABLE
 , ID_TIPO_FERIADO                  NUMBER(3,0)        NOT NULL ENABLE -- 1 NACIONAL, 2 ESTADUAL, 3 MUNICIPAL, 4 OUTROS
 , OBS                              NVARCHAR2(15)
 , CONSTRAINT PK_FERIADO_ID_FERIADO PRIMARY KEY (ID_FERIADO)
 , CONSTRAINT UQ_FERIADO_DATA UNIQUE (DATA)
);

-- DROP SEQUENCE FERIADO_FCSEQ; 
CREATE SEQUENCE FERIADO_FCSEQ
INCREMENT BY 1
START WITH 1
NOCYCLE;

-- DROP TRIGGER TG_FERIADO_ID_FERIADO_BI;
CREATE OR REPLACE TRIGGER TG_FERIADO_ID_FERIADO_BI BEFORE INSERT ON FERIADO
FOR EACH ROW
 WHEN (new.ID_FERIADO IS NULL) BEGIN
  SELECT FERIADO_FCSEQ.NEXTVAL INTO :new.ID_FERIADO FROM dual;
END;
/
ALTER TRIGGER TG_FERIADO_ID_FERIADO_BI ENABLE;


/* Se desejar usar o o arquivo CSV dos feriados chamado FERIADOS.CSV com CRLF no final de cada linha, use o SQL Loader do Oracle para dá carga do arquivo, evitando assim digitação de datas, é possível obtê-lo CLICANDO AQUI! */
/* Criando o arquivo de controle chamado FERIADO.CTL salvo no diretorio C:\TEMP */
load data
  infile 'FERIADO.CSV'
  into table feriado
  fields terminated by "|"
  (
      data  DATE "YYYY-MM-DD"
    , descricao
    , id_tipo_feriado
    , obs
  )
/* Depois executar o SQL Loader, no Linux é igual ao do Windows considerando nome da pasta, no Windows fica assim: */
/* Lembrando de considerar, isto é, permutar seu usuario e senha, ip_servidor e SID do Oracle do seu servidor*/
sqlldr usuario/senha@ip_servidor/SID control=FERIADO.CTL log=X.LOG bad-Z.BAD READSIZE=10000000


/* Depois criamos uma store function para idenficar dias feriados usando a tabela feriado conforme script abaixo: */


CREATE OR REPLACE FUNCTION usf_feriado (d in date) 
RETURN integer 
AS
  
  x integer; 

BEGIN 

  SELECT count(*) 
    INTO x
    FROM feriado 
   WHERE to_char(data,'YYYY-MM-DD') = to_char(d,'YYYY-MM-DD'); 
   
  IF (x >= 1) THEN 
      RETURN 1;
  ELSE 
      RETURN 0; 
  END IF;
  
END usf_feriado; 



/* Logo em seguida criamos um store function para tratar o ultimo dia util, conforme script abaixo: */


CREATE OR REPLACE FUNCTION usf_ultimo_dia_util ( dt_base in date ) 
RETURN date 
AS

  dt_basex date; 
  bo_fimx  boolean; 

BEGIN 

  dt_basex := dt_base; 
  bo_fimx  := false; 
  
  WHILE NOT (bo_fimx) LOOP 
  
      bo_fimx := to_char(dt_basex,'d') NOT IN ('1','7');
      
      IF usf_feriado(dt_basex) = 1 THEN 
          bo_fimx := false;
      END IF; 
      
      IF NOT (bo_fimx) THEN 
          dt_basex := dt_basex - 1; 
      END IF; 
      
  END LOOP; 
  
  RETURN dt_basex; 
  
EXCEPTION 

  WHEN others THEN 
  RAISE; 
  
  
END usf_ultimo_dia_util;


/* Testando o uso da function em SQL puro */


SELECT usf_feriado(sysdate) AS DT FROM DUAL; -- RETORNA 1 PARA FERIADO E 0 PARA OUTROS DIAS 

ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'; -- ALTERA DATA PARA FORMATO 'YYYY-MM-DD'

SELECT usf_ultimo_dia_util ('2015-04-05') from dual; -- RETORNA O ULTIMO DIA UTIL -> 2015-04-02

/* Espero ter ajudado! */

/* Seja Feliz!! */

/* APdSJC */

quarta-feira, 9 de julho de 2014

Como Listar Estrutura de Campos e Tabelas via query em SQL Server

Geralmente quando queremos saber informações sobre colunas e tabelas, no SQL Server usamos a store procedure sp_help [nome_tabela], mas o objetivo dessa query é filtrar determinadas condições a exemplo de tamanho de identificadores superiores a 30 caracteres, o clássico erro ORA-00972: identifier is too long. do Oracle, para quem trabalha com sistemas Multi SGBDR ou migração de dados, essa query resolve essa e outras perguntas.

Segue:

SELECT TABLE_CATALOG              AS BD
     , TABLE_SCHEMA               AS ESQUEMA_TABELA
     , TABLE_NAME                 AS TABELA 
     , COLUMN_NAME                AS COLUNA 
     , ORDINAL_POSITION           AS ORD_POS
     , DATA_TYPE                  AS TIPO 
     , CHARACTER_MAXIMUM_LENGTH   AS TAM_CARACTER
     , DATETIME_PRECISION         AS TAM_DATA
     , NUMERIC_PRECISION          AS TAM_NUMERICO
     , CASE WHEN CHARACTER_MAXIMUM_LENGTH  IS NOT NULL THEN
                CAST(CHARACTER_MAXIMUM_LENGTH AS NUMERIC(16,6))
            WHEN DATETIME_PRECISION IS NOT NULL THEN
                CAST(DATETIME_PRECISION AS NUMERIC(16,6))
            ELSE
                CAST(CAST(NUMERIC_PRECISION AS VARCHAR) + '.' + CAST( NUMERIC_SCALE AS VARCHAR) AS NUMERIC(16,6))
       END                        AS TAM
     , CASE WHEN IS_NULLABLE = 'YES' THEN
           'SIM'
       ELSE
           'NÃO'
       END                        AS [NULO?]
     , COLLATION_NAME             AS COLLATION
     , LEN(COLUMN_NAME)           AS TAM_NOME_COLUNA 
     , LEN(TABLE_NAME)            AS TAM_NOME_TABELA 
  FROM INFORMATION_SCHEMA.COLUMNS
 WHERE 1=1 
   --Testa condição de identificadores maior que 30 caracteres usado na migração para Oracle ou sistemas multi SGBDR
   --O clássico erro ORA-00972: identifier is too long. do Oracle, para quem trabalha com sistemas Multi SGBDR ou migração dados.
   --AND LEN(COLUMN_NAME) > 30 OR  LEN( TABLE_NAME) > 30 
   --Testa por nome de tabela   
   --AND TABLE_NAME  = 'NOME_TABELA'
   --Testa por coluna (campo) 
   --AND COLUMN_NAME = 'NOME_COLUNA'

Mais uma vez, espero ter ajudado. Seja feliz e fique na Paz de Jesus Cristo.

sexta-feira, 29 de novembro de 2013

Desenvolvendo Querys Compativeis com Todos os SGBDRs com Ajuda do SQL Fiddle

Desenvolvendo Querys Compativeis com Todos os SGBDRs com Ajuda do SQL Fiddle


Sabe quando um amigo lhe pede uma ajuda sobre como desenvolver uma determinada query e você não sabe como explicar, essa é a dica para quem já passou por esse tipo de problema chama-se SQL Fiddle
Muitas vezes não é possível testar uma determinada query por não ter o SGBDR instalado ou está sem uma conexão segura ao SGBDR, então a dica é usar o SQL Fiddle.
Nesse site http://sqlfiddle.com/ ainda existe a possibilidade de verificar como funciona a mesma query nos diversos SGBDRs e suas diversas versões, uma feature interessante para quem desenvolve sistemas multi-SGBDRs.

Segue a dica para trabalhar com SQL Fiddle.

Acessar o SQL Fiddle no seguinte site: http://sqlfiddle.com/ Na primeira coluna coloca-se os comandos DDL (de criação de estrutura, tabelas, views, etc).
Executar com o botão Run Schema.
Na segunda coluna coloca-se os comandos DML (insert, update, delete, selects).
Executar com o botão Run SQL.
Outra observação é que o SQL Fiddle não armazena o cache dos scripts, então há de se rodar toda a query de uma única vez.

Mais uma vez espero ter ajudado.

APdSJC!

terça-feira, 29 de janeiro de 2013

Desenvolvendo querys SQL para Razão e Balancete Contábil.

Desenvolvendo querys SQL para Razão e Balancete Contábil.

Em um artigo escrito neste blog no dia 06-09-2012 Consulta SQL de Plano de Contas - Query Contabil - Query para Centro de Custo conforme link http://www.emersonhermann.blogspot.com.br/2012/09/consulta-sql-de-plano-de-contas-query.html, mostrei como desenvolver uma query em uma estrutura de plano de contas ou centro de custo, dessa vez irei apresentar de forma prática, gradual e por exemplos de como desenvolver uma query para relatório de Razão, Razão Sumarizado e Balancete Contábil.

Nivel de Complexidade: Intermediário, Avançado

Quem desenvolve sabe como é complicado criar relatórios para contabilidade ou centro de custos, seja codificando em alguma linguagem ou mesmo tentando encurtar o tempo ou a pressão, usando algum gerador de relatórios, a exemplo do MS Report Service, SAP Crystal Reports, Script Case, etc.

As querys scripts mostradas nesse artigo foram desenvolvidas para os seguintes SGBDRs em ordem alfabética:

Firebird 2.5.1
Oracle 11g R2
Postgres 9.1
SQL Server 2012

A modelagem aqui apresentada não seguiu o rigor acadêmico, a exemplo de implementação de constraints, chaves primárias, etc, bem como os exemplos citados para area Contabil.

O objetivo principal deste artigo é mostrar como desenvolver querys para Sistemas Contabeis, houve uma simplificação com intuíto de facilitar o entendimento, entretanto, com os exemplos expostos é possivel adotar em qualquer modelo relacional.

Houve também uma preocupação em apresentar os scripts desenvolvidos nos SGBDRs citados no inicio deste documento.

Pode-se chegar aos mesmos resultados de uma forma mais performática e simples; estou apto a sugestões.

Seguem os exemplos em scripts SQL:

Criando as tabelas ... (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1, SQL Server 2012)

-- USE tempdb; -- Descomentar caso use SQL Server, recomendo criar um banco de teste para os outros SGBDRs.
--DROP TABLE plano_conta;
CREATE TABLE plano_conta
( 
   id_plano_conta   varchar(12) PRIMARY KEY   -- dados da conta ex. 1.02.01 
 , descricao        varchar(50)               -- descricao da conta cadastrada ex. Vendas Externas
 , tipo_conta       varchar(1)                -- tipo de conta do cc Analitica ou Sintética, dominio discreto: A ou S, em situação de produção merece uma constraint check
); 
 
--DROP TABLE lancamento;
CREATE TABLE lancamento 
(
   id_lancamento    integer   PRIMARY KEY    -- id do lancamento, recomenda-se auto incremento, mas para simplifcar fica sem auto incremento
 , dt_lancamento    date                     -- data do lancamento 
 , numero_doc       varchar(40)              -- numero do documento a ser informado  
 , id_plano_conta   varchar(12)              -- chave estrangeira para a tabela plano_conta, mas para simplificar apenas iremos convencionar, não será habilitado a FK, recomendo colocar not null
 , tipo_lancamento  varchar(1)               -- tipo de lancamento 'E' = Entrada 'S' = Saida 
 , historico        varchar(100)             -- historico do lancamento 
 , valor_lancamento numeric(15,2)            -- valor informado 
);

Povoando os tabelas...
-- Receitas 
 
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1','Receita','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.1','Vendas Internas','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.1.1','Escola','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.1.2','Escritório','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.2','Vendas Externas','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.2.1','Livro','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('1.2.2','Brinquedos','A');
 
-- Despesas
 
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2','Despesas','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.1','Fornecedores','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.1.1','Nacional','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.1.2','Importado','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.2','Escritório','S');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.2.1','Materiais de limpeza','A');
INSERT INTO plano_conta (id_plano_conta, descricao, tipo_conta) VALUES ('2.2.2','Materiais de Escritório','A');
 
-- Vamos povoar a tabela lancamento: 
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (1,'2012-07-03','0000084','1.2.2','E',NULL,10.55); 
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (2,'2012-07-03','0000084','1.2.2','S',NULL,2.50); 
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (3,'2012-07-01','0000021','1.1.2','E',NULL,50.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento,numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (4,'2012-07-01','0000042','1.2.2','E',NULL,100.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (5,'2012-07-04','0000084','1.2.2','E',NULL,160.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (6,'2012-07-04','0000084','1.2.2','S',NULL,80.00);
 
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (7,'2012-07-04','0000142','2.2.1','S',NULL,40.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (8,'2012-07-07','0000210','2.2.2','S',NULL,80.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (9,'2012-07-13','0000242','2.2.2','S',NULL,20.00);
INSERT INTO lancamento (id_lancamento, dt_lancamento, numero_doc, id_plano_conta, tipo_lancamento, historico, valor_lancamento) VALUES (10,'2012-07-13','0000284','2.2.1','S',NULL,15.00);



Vamos as querys relatórios...

Razão Detalhado (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1, SQL Server 2012)
-- razao detalhado (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1, SQL Server 2012) 

   SELECT lan.id_lancamento
        , lan.dt_lancamento 
        , lan.numero_doc
        , lan.id_plano_conta
        , lan.tipo_lancamento
        , lan.historico 
        , 
          coalesce(
          (
          SELECT sum
                 ( 
                  CASE WHEN tipo_lancamento = 'E' THEN 
                            valor_lancamento
                       WHEN tipo_lancamento = 'S' THEN 
                            valor_lancamento * -1 
                       ELSE 
                            0.00
                  END
                 ) 
            FROM lancamento 
            WHERE dt_lancamento < lan.dt_lancamento 
              AND id_plano_conta  = lan.id_plano_conta 
          ),0)  AS saldo_inicial  
        , CASE WHEN tipo_lancamento = 'E' THEN 
                    valor_lancamento
               ELSE 
                    0.00 
          END AS entrada 
        , CASE WHEN tipo_lancamento = 'S' THEN 
                    valor_lancamento
               ELSE 
                    0.00 
          END AS saida 
        ,  
          coalesce(
          (
          SELECT sum
                 ( 
                  CASE WHEN tipo_lancamento = 'E' THEN 
                            valor_lancamento 
                       WHEN tipo_lancamento = 'S' THEN 
                            valor_lancamento * -1 
                       ELSE 
                            0.00
                  END
                 ) 
            FROM lancamento
           WHERE dt_lancamento <= lan.dt_lancamento 
             AND id_plano_conta  = lan.id_plano_conta 
          ),0)  AS saldo_final
     FROM lancamento AS lan
     JOIN plano_conta AS plc 
       ON plc.id_plano_conta  = lan.id_plano_conta
    WHERE lan.dt_lancamento >= '2012-07-04'
      AND lan.dt_lancamento <= '2012-07-14'
      AND lan.id_plano_conta  = '2.2.2'
 ORDER BY lan.dt_lancamento ASC 
        ;


Razão Sumarizado Por Plano de Conta (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1, SQL Server 2012)
-- razao sumarizado por plano de conta (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1, SQL Server 2012)   
    SELECT x.id_plano_conta
         , pcx.descricao 
         , coalesce(
           (
            SELECT sum
                   ( 
                    CASE WHEN tipo_lancamento = 'E' THEN 
                              valor_lancamento
                         WHEN tipo_lancamento = 'S' THEN 
                              valor_lancamento * -1 
                         ELSE 
                              0.00
                     END
                   ) 
              FROM lancamento 
             WHERE dt_lancamento < '2012-07-04'
               AND id_plano_conta  = x.id_plano_conta 
           ),0)  AS saldo_inicial 
         , sum(x.entrada) AS entrada
         , sum(x.saida)   AS saida
         , coalesce(
           (
            SELECT sum
                   ( 
                    CASE WHEN tipo_lancamento = 'E' THEN 
                              valor_lancamento 
                         WHEN tipo_lancamento = 'S' THEN 
                              valor_lancamento * -1 
                         ELSE 
                              0.00
                    END
                   ) 
              FROM lancamento
             WHERE dt_lancamento <=  '2012-07-14'
               AND id_plano_conta  = x.id_plano_conta 
           ),0)  AS saldo_final
      FROM
         ( 
           SELECT lan.id_plano_conta
                , CASE WHEN tipo_lancamento = 'E' THEN 
                            valor_lancamento
                       ELSE 
                            0.00 
                  END AS entrada 
                , CASE WHEN tipo_lancamento = 'S' THEN 
                            valor_lancamento
                       ELSE 
                            0.00 
                  END AS saida 
             FROM lancamento AS lan
             JOIN plano_conta AS plc 
               ON plc.id_plano_conta  = lan.id_plano_conta
            WHERE lan.dt_lancamento >= '2012-07-04'
              AND lan.dt_lancamento <= '2012-07-14'
              AND lan.id_plano_conta  = '2.2.2'
         ) AS x
      JOIN plano_conta AS pcx
        ON pcx.id_plano_conta = x.id_plano_conta 
  GROUP BY x.id_plano_conta
         , pcx.descricao
  ORDER BY x.id_plano_conta ASC 
      ;


Balancete Contabil (Script para SQL Server 2012)
-- balancete contabil (Script para SQL Server 2012) 
  SELECT pcx.id_plano_conta
       , pcx.descricao 
       , sum(xx.saldo_inicial) AS saldo_inicial 
       , sum(xx.entrada)       AS entrada
       , sum(xx.saida)         AS saida 
       , sum(xx.saldo_final)   AS saldo_final 
    FROM
       (
        SELECT x.id_plano_conta
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'E' THEN 
                                  valor_lancamento
                             WHEN tipo_lancamento = 'S' THEN 
                                  valor_lancamento * -1 
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento < '2012-07-04'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saldo_inicial 
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'E' THEN 
                                  valor_lancamento
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento >= '2012-07-04'
				   AND dt_lancamento <= '2012-07-14'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS entrada
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'S' THEN 
                                  valor_lancamento 
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento >= '2012-07-04'
				   AND dt_lancamento <= '2012-07-14'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saida			 
             , coalesce(
               (
                 SELECT sum
                        ( 
                         CASE WHEN tipo_lancamento = 'E' THEN 
                                   valor_lancamento 
                              WHEN tipo_lancamento = 'S' THEN 
                                   valor_lancamento * -1 
                              ELSE 
                                   0.00
                         END
                        ) 
                   FROM lancamento
                  WHERE dt_lancamento <=  '2012-07-14'
                    AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saldo_final
          FROM
             ( 
               SELECT pla.id_plano_conta
			        , lan.dt_lancamento
                    , CASE WHEN lan.tipo_lancamento = 'E' THEN 
                                lan.valor_lancamento
                           ELSE 
                                0.00 
                      END AS entrada 
                    , CASE WHEN lan.tipo_lancamento = 'S' THEN 
                                lan.valor_lancamento
                           ELSE 
                                0.00 
                      END AS saida 
                 FROM lancamento AS lan
				 JOIN plano_conta AS pla
				   ON pla.id_plano_conta = lan.id_plano_conta 
                WHERE 1=1 
             ) AS x
      GROUP BY x.id_plano_conta
       ) AS xx
    JOIN plano_conta pcx 
      ON xx.id_plano_conta LIKE pcx.id_plano_conta + '%'
GROUP BY pcx.id_plano_conta 
       , pcx.descricao 
ORDER BY pcx.id_plano_conta ASC
       ;   


Balancete Contabil (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1)
  
-- balancete contabil (Script para Firebird 2.5.1, Oracle 11g R2, Postgres 9.1)   
  SELECT pcx.id_plano_conta
       , pcx.descricao 
       , sum(xx.saldo_inicial) AS saldo_inicial 
       , sum(xx.entrada)       AS entrada
       , sum(xx.saida)         AS saida 
       , sum(xx.saldo_final)   AS saldo_final 
    FROM
       (
        SELECT x.id_plano_conta
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'E' THEN 
                                  valor_lancamento
                             WHEN tipo_lancamento = 'S' THEN 
                                  valor_lancamento * -1 
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento < '2012-07-04'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saldo_inicial 
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'E' THEN 
                                  valor_lancamento
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento >= '2012-07-04'
				   AND dt_lancamento <= '2012-07-14'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS entrada
             , coalesce(
               (
                SELECT sum
                       ( 
                        CASE WHEN tipo_lancamento = 'S' THEN 
                                  valor_lancamento 
                             ELSE 
                                  0.00
                        END
                       ) 
                  FROM lancamento 
                 WHERE dt_lancamento >= '2012-07-04'
				   AND dt_lancamento <= '2012-07-14'
                   AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saida			 
             , coalesce(
               (
                 SELECT sum
                        ( 
                         CASE WHEN tipo_lancamento = 'E' THEN 
                                   valor_lancamento 
                              WHEN tipo_lancamento = 'S' THEN 
                                   valor_lancamento * -1 
                              ELSE 
                                   0.00
                         END
                        ) 
                   FROM lancamento
                  WHERE dt_lancamento <=  '2012-07-14'
                    AND id_plano_conta  = x.id_plano_conta 
               ),0)  AS saldo_final
          FROM
             ( 
               SELECT pla.id_plano_conta
			        , lan.dt_lancamento
                    , CASE WHEN lan.tipo_lancamento = 'E' THEN 
                                lan.valor_lancamento
                           ELSE 
                                0.00 
                      END AS entrada 
                    , CASE WHEN lan.tipo_lancamento = 'S' THEN 
                                lan.valor_lancamento
                           ELSE 
                                0.00 
                      END AS saida 
                 FROM lancamento AS lan
				 JOIN plano_conta AS pla
				   ON pla.id_plano_conta = lan.id_plano_conta 
                WHERE 1=1 
             ) AS x
      GROUP BY x.id_plano_conta
       ) AS xx
    JOIN plano_conta pcx 
      ON xx.id_plano_conta LIKE pcx.id_plano_conta || '%'
GROUP BY pcx.id_plano_conta 
       , pcx.descricao 
ORDER BY pcx.id_plano_conta ASC
       ; 


Figura 01 - Resultado das Querys

Para facilitar, caso haja interesse, recomendo criar views ou functions ou procedures das querys acimas, pois são demasiadamente extensas.

Mais uma vez espero ter ajudado.

APDSJ!

quinta-feira, 6 de setembro de 2012

Consulta SQL de Plano de Contas - Query Contabil - Query para Centro de Custo

A idéia primordial desse artigo é demonstrar como desenvolver uma query sql usando um plano de contas ou centro de custo, o principio é o mesmo, subtotalizando de forma invertida, considerando uma estrutura de balancete ou centro de custo, mas sempre usando um plano de contas com contas analiticas e sintéticas e vários niveis de sub-contas.

O SGBDR testados foram:
 Firebird 2.5.1
 Postgres 9.1
 SQL Server 2012
 Oracle 11g R2

Expondo o problema, exemplo:

Montar uma query relatório que mostre o resultado totalizado por níveis de contas lançadas.
O centro de custo irá ser lançado sempre no ultimo nivel e/ou conta analitica, ou seja 1.1.1 ou 1.2.1, etc. 

Conforme figura Figura 01, abaixo:

Figura 01 - Relatório Sumarizado por Plano de Contas

Temos uma estrutura de centro de custo modelada da seguinte maneira: 

Script para Firebird 2.5.1, Postgres 9.1, SQL Server 2012, Oracle 11g R2



-- USE tempdb; -- Descomentar caso use SQL Server 
--DROP TABLE centro_custo;
CREATE TABLE centro_custo
( 
   id_centro_custo  varchar(12) PRIMARY KEY   -- dados da conta ex. 1.02.01 
 , descricao        varchar(50)               -- descricao da conta cadastrada ex. Vendas Externas
 , tipo_conta       varchar(1)                -- tipo de conta do cc Analitica ou Sintética, dominio discreto: A ou S, em situação de produção merece uma constraint check
); 

--DROP TABLE movimento;
CREATE TABLE movimento 
(
   id_movimento   integer   PRIMARY KEY  -- id do movimento, recomenda-se auto incremento, mas para simplifcar fica sem auto incremento
 , numero_doc   varchar(40)              -- numero do documento a ser informado  
 , id_centro_custo   varchar(12)         -- chave estrangeira para a tabela centro de custo, mas para simplificar apenas iremos convencionar, não será habilitado a FK, recomendo colocar not null
 , valor_movimento numeric(15,2)         -- valor informado 
);

Agora iremos povoar a tabela de centro de custo

-- Receitas 

INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1','Receita','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.1','Vendas Internas','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.1.1','Escola','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.1.2','Escritório','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.2','Vendas Externas','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.2.1','Livro','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('1.2.2','Brinquedos','A');

-- Despesas

INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2','Despesas','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.1','Fornecedores','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.1.1','Nacional','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.1.2','Importado','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.2','Escritório','S');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.2.1','Materiais de limpeza','A');
INSERT INTO centro_custo (id_centro_custo, descricao, tipo_conta) VALUES ('2.2.2','Materiais de Escritório','A');

-- Vamos povoar a tabela movimento: 

INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (1,'0000021','1.1.2',50.00);
INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (2,'0000042','1.2.2',100.00);
INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (3,'0000084','1.2.2',160.00);

INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (4,'0000142','2.2.1',40.00);
INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (5,'0000210','2.2.2',80.00);
INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (6,'0000242','2.2.2',20.00);
INSERT INTO movimento (id_movimento, numero_doc, id_centro_custo, valor_movimento) VALUES (7,'0000284','2.2.1',15.00);

Listando os centros de custos cadastrados ...
-- Listando conteudo de centro_custo 
SELECT * FROM centro_custo ORDER BY 1;
Figura 02 - Lista de Centro Custo

Listando os movimentos cadastrados, referenciando os centros de custos ...
-- Listando conteudo de movimento 
SELECT * FROM movimento;
Figura 03 - Lista de Movimento Script apenas para SQL Server 2012

-- Query SQL Centro de Custo, para SQL Server 2012, exemplo: 
  SELECT cc.id_centro_custo
       , cc.descricao 
       , sum(m.valor_movimento) AS total_conta 
    FROM centro_custo cc 
    JOIN movimento m
      ON m.id_centro_custo LIKE cc.id_centro_custo + '%'  -- O segredo está aqui, o campo id_centro_custo vem depois do LIKE
GROUP BY cc.id_centro_custo 
       , cc.descricao 
ORDER BY cc.id_centro_custo ASC
       ; 
Figura 04 - Query Centro Custo com Resultado em SQL Server 2012

Script apenas para Firebird 2.5.1, Postgres 9.1, Oracle 11g R2
  
-- Query SQL Centro de Custo, para Firebird 2.5.1, Postgres 9.1, Oracle 11g R2, exemplo: 
  SELECT cc.id_centro_custo
       , cc.descricao 
       , sum(m.valor_movimento) AS total_conta 
    FROM centro_custo cc 
    JOIN movimento m
      ON m.id_centro_custo LIKE cc.id_centro_custo || '%'  -- O segredo está aqui, o campo id_centro_custo vem depois do LIKE
GROUP BY cc.id_centro_custo 
       , cc.descricao 
ORDER BY cc.id_centro_custo ASC
       ; 
Figura 05 - Query Centro Custo com Resultado em Oracle 11g R2


A grande dica está na junção dos campos de conta usando like concatenado com '%' no final

Como no exemplo com Oracle 11g R2, abaixo descrito:

ON m.id_centro_custo LIKE cc.id_centro_custo || '%'

Existem outras formas de se chegar ao mesmo resultado, uma delas seria implementar union em contas de grupo e depois criar uma view, mas, fica complicado e não elegante, já que, será necessário alterar a query toda vez que o plano de contas mudar a estrutura.

Outra forma seria usar querys recursivas, que seria bem mais elegante que a opção anterior, entretanto, mais complexa, mas quanto ao uso de recursividade em querys, nem todos os SGBDRs atualmente dão suporte a essa técnica, outro problema reside no fato do desempenho e consumo de recursos, pois quanto mais níveis tiver o plano de contas maior será a pilha, em outras palavras, consumo de memória e processamento no servidor do banco de dados alto.

Eu particularmente já tive a oportunidade fazer parte de uma equipe de desenvolvimento, em que o meu chefe e a própria equipe insistiram em traçar uma modelagem que usava querys recursivas, apesar de não concordar, como era novato na equipe, não me deram crédito, então me reservei a sabedoria do silêncio e mesmo não concordando aproveitei a oportunidade para fazer acontecer e vê como ficaria um sistema de custos com uso maciço de querys recursivas, foi divertido, mas ainda não recomendo, pois a complexidade é alta das querys recursivas e da codificação da aplicação também, tornando o compartilhamento do conhecimento difícil, como também a manutenção da aplicação, considerando ainda o consumo extremo de memória e processamento a nível de infra-estrutura.

Mais uma vez espero ter ajudado.


Fique na Paz do Senhor Jesus Cristo !!!

terça-feira, 9 de agosto de 2011

Querys Recursivas no Oracle





Querys Recursivas no Oracle

Segue um exemplo prático de como fazer querys recursivas no Oracle, usando genealogia.

Recomendado para quem está estudando para a obtenção da Certificação Oracle Database: SQL Expert (OCE – Oracle Certified Expert), Exame 1Z0-047 Oracle Database SQL Expert.


--
-- Nome Artefato/Programa..: querys_recursivas_no_oracle 
-- Empresa.................: 
-- Autor(es)...............: Emerson Hermann (emersonhermann@gmail.com) 
-- Data Inicio ............: 07/04/2011
-- Data Atual..............: 22/07/2011
-- Versao..................: 0.01
-- Compilador/Interpretador: Oracle
-- Sistemas Operacionais...: Linux/Windows/Outros SOs
-- SGBD....................: Oracle 9i/10g/11g
-- Kernel..................: Nao informado!
-- Finalidade..............: uso de querys recursivas no oracle com com start with ... connect by ... 
-- ........................: 
-- OBS.....................: 
--


/* testando no oracle com start with ... connect by */

--DROP TABLE genealogia;
CREATE TABLE genealogia
(
    id_genealogia integer     PRIMARY KEY 
  , nome varchar2(25)         NOT NULL
  , id_genealogia_pai integer NULL --FOREIGN KEY fk_genealogia REFERENCES genealogia(id_genealogia)

);

--TRUNCATE TABLE genealogia;

SELECT * FROM genealogia;

INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (1,'ABRAÃO',NULL);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (2,'ISAC',1);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (3,'ESAÚ',2);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (4,'JACÓ',2);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (5,'RÚBEN',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (6,'SIMEÃO',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (7,'LEVI',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (8,'JUDÁ',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (9,'ISSACAR',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (10,'ZEBULON',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (11,'JOSÉ',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (12,'BENJAMIM',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (13,'DÃ',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (14,'NAFTALI',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (15,'GADE',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (16,'ASER',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (17,'DINÁ',4);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (18,'PEREZ',8);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (19,'ZERA',8);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (20,'ESRON',18);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (21,'ARÃO ',20);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (22,'AMINADABE',21);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (23,'NASSON',22);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (24,'SALMON',23);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (25,'BOAZ',24);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (26,'OBEDE',25);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (27,'JESSÉ',26);
INSERT INTO genealogia (id_genealogia, nome, id_genealogia_pai) VALUES (28,'DAVI',27);

SELECT * FROM genealogia;


--query 1, AUTO RELACIONAMENTO

            SELECT g1.nome
                 , g1.id_genealogia
                 , g2.id_genealogia_pai 
              FROM genealogia g1
         LEFT JOIN genealogia g2 
                ON g1.id_genealogia = g2.id_genealogia_pai 
                 ;   

--query 2, CONNECT BY PRIOR

            SELECT nome
                 , id_genealogia
                 , id_genealogia_pai 
              FROM genealogia
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
                 ;   

--query 3, LEVEL              

            SELECT nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL 
              FROM genealogia
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
                 ;   

--query 4,  START WITH

            SELECT nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL
              FROM genealogia
        START WITH id_genealogia = 4  --JACÓ
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
          ORDER BY LEVEL ASC
                 ;
                 
--query 5, COM ARVORE

            SELECT RPAD(LPAD(' ', 5*(LEVEL-1))||nome,30) AS arvore  
                 , nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL
              FROM genealogia
        START WITH id_genealogia = 1
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
          ORDER BY LEVEL ASC
                 ;

--query 6, SYS_CONNECT_BY_PATH

            SELECT LPAD(' ', 5*(LEVEL-1)) || nome AS representacao_arvore1
                 , SYS_CONNECT_BY_PATH(nome, '/') AS represencao_arvore2  
                 , nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL
              FROM genealogia
        START WITH id_genealogia = 1
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
          ORDER BY LEVEL ASC
                 ;

--query 7, ORDER SIBLINGS BY

            SELECT LPAD(' ', 5*(LEVEL-1)) || nome AS representacao_arvore1
                 , SYS_CONNECT_BY_PATH(nome, '/') AS represencao_arvore2  
                 , nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL
              FROM genealogia
        START WITH id_genealogia = 1
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
 ORDER SIBLINGS BY nome ASC
                 ;
                 
--query 8, CONNECT_BY_ROOT

CREATE OR REPLACE  VIEW  vw_genealogia  AS 
            SELECT LPAD('>', 5*(LEVEL-1)) || nome AS representacao_arvore1
                 , SYS_CONNECT_BY_PATH(nome, '\') AS represencao_arvore2  
                 , CONNECT_BY_ROOT nome AS raiz 
                 , nome
                 , id_genealogia
                 , id_genealogia_pai 
                 , LEVEL AS nivel 
              FROM genealogia
        START WITH id_genealogia = 1
--CONNECT BY NOCYCLE PRIOR  id_genealogia = id_genealogia_pai
  CONNECT BY PRIOR id_genealogia = id_genealogia_pai
 --ORDER SIBLINGS BY level  ASC
ORDER  BY level  ASC;

SELECT * FROM vw_genealogia;

Sem stress...

sexta-feira, 24 de junho de 2011

Flashback Query no Oracle 11g


O Oracle 11g implementa várias tecnologias de Flashback como Flashback Database, Flashback Table, Flashback Drop entre outros,
abordarei o uso do recurso de Flashback Query.

Introduzido com o Oracle 9i, este recurso fornece a habilidade de visualizar os dados como eles estavam em um determinado tempo no passado.
Por padrão, operações no banco de dados usam os dados disponíveis mais recentemente "comitados".
Se você quiser pesquisar determinados dados em algum ponto no passado, você precisará utilizar o recurso de Flashback Query
na qual será necessário especificar um "horário" ou um SCN (System change Number) para efetuar a pesquisa.

Este recurso também é muito útil, quando você precisa restaurar dados que foram erroneamente deletados ou alterados.
Antes da versão Oracle 9i, você tinha que recuperar o banco de dados até um determinado ponto que lhe interessasse.
Dependendo do tamanho do banco de dados, este processo poderia ser lento e demorado.

Apenas para elucidar uma situação em que muitos DBAs, já passaram ou poderão passar, vou ilustrar um diálogo entre Usuário e DBA:

Usuário: meus dados sumiram, pode me ajudar?
DBA: o que vc fez?
Usuário: fiz um delete e esqueci de colocar where
DBA: vc deu commit ?
Usuario: claro!
DBA: humm...

Este artigo é para quem já passou por isso ou ainda vai passar usando um SGBDR Oracle.

Antes de mais nada, para você poder usar o recurso de Flashback Query, é necessário configurar o seu banco de dados para usar o gerenciamento automático de UNDO (Automatic Undo Management).

Verifique se o seu banco de dados já está com esta configuração setada, caso contrário, altere o parâmetro com o valor e privilégios apropriados.

Conforme script abaixo:
-- É necessário configurar o seu banco de dados para usar o gerenciamento automático de UNDO (Automatic Undo Management).
-- Checando parametros, verificando se está setado para Flashback

c:\>sqlplus /nolog

CONNECT / AS SYSDBA;

show parameter undo_management;

-- No parâmetro abaixo, o valor é especificado (em segundos) no qual está no valor padrão 900,  15 minutos de retenção de dados de undo.

show parameter undo_retention;

CREATE USER emerson IDENTIFIED BY emerson DEFAULT TABLESPACE users QUOTA UNLIMITED ON users;

GRANT CONNECT TO emerson;

show user;

CONNECT / AS SYSDBA;

show user;

-- dando permissões 

GRANT EXECUTE ON dbms_flashback TO emerson;
GRANT CREATE ANY TABLE TO emerson;
GRANT COMMENT ANY TABLE TO emerson;

CONNECT emerson/emerson@orcl;

-- criando a tabela
-- DROP TABLE produto;
CREATE TABLE produto
(
  cod  NUMBER PRIMARY KEY,
  data DATE,
  descricao VARCHAR2 (100)
);

-- inserindo registros ...
INSERT INTO produto VALUES (1, sysdate, 'Computador');
INSERT INTO produto VALUES (2, sysdate, 'Laptop');
INSERT INTO produto VALUES (3, sysdate, 'Impressora');
INSERT INTO produto VALUES (4, sysdate, 'Monitor');
INSERT INTO produto VALUES (5, sysdate, 'Mouse');

COMMIT;

-- listando a tabela produto com detalhes de horas e minutos e segundos
SELECT cod, to_char(data,'dd/mm/yyyy hh24:mi:ss') data, descricao FROM produto; 

-- esperar um tempo para inserir estes para simular um recuperação baseada no tempo
INSERT INTO produto VALUES (6, sysdate, 'Teclado');
INSERT INTO produto VALUES (7, sysdate, 'HD');
INSERT INTO produto VALUES (8, sysdate, 'Processador');

COMMIT;

-- listando a tabela produto com detalhes de horas e minutos e segundos
SELECT cod, to_char(data,'dd/mm/yyyy hh24:mi:ss') data, descricao FROM produto; 

-- apenas para entender como funciona as datas
SELECT SYSTIMESTAMP, (to_timestamp('02/06/2011 13:37:07','DD/MM/YYYY HH24:MI:SS')) FROM dual;
SELECT SYSTIMESTAMP FROM dual; -- mesma coisa que sysdate porem com horas e fuso horario

-- habilitando a linha do tempo no flashback, altera tempo conf. necessidade
EXECUTE dbms_flashback.enable_at_time (to_timestamp('02/06/2011 13:37:07','DD/MM/YYYY HH24:MI:SS'));
-- EXECUTE dbms_flashback.enable_at_time (SYSTIMESTAMP - 60); -- mesma coisa de outra forma,  também  em minutos

COMMIT;

SELECT cod, to_char(data,'dd/mm/yyyy hh24:mi:ss') data, descricao FROM produto;

-- disabilitando o flashback
EXECUTE dbms_flashback.disable;

-- listando a tabela produto com detalhes de horas e minutos e segundos
SELECT cod, to_char(data,'dd/mm/yyyy hh24:mi:ss') data, descricao FROM produto;

-- linha do tempo para recuperação
SELECT * FROM produto AS OF TIMESTAMP (to_timestamp('02/06/2011 13:37:07','DD/MM/YYYY HH24:MI:SS'));  

-- mesma coisa de outra forma, linha do tempo para recuperação 1 minuto
-- SELECT * FROM produto AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' MINUTE); 


Referencias:
http://eduardolegatti.blogspot.com/2007/05/utilizando-flashback-query-no-oracle-9i.html
http://www.dbasupport.com/oracle/ora11g/Flashback-TIMESTAMP-or-SCN.shtml
http://www.eduardomorelli.com/
Oracle 9i, SQL PL/SQL e Administração - Morelli, Eduardo
Dominando Oracle 9i - Modelagem e Desenvolvimento - Fanderuff, Damaris
OCA Oracle Database 11g Administração I ( Guia do Exame 1Z0-052 ) - Watson, John

Instalando Oracle 11g no Windows 7

Segue os links de como instalar Oracle 11g no Windows 7, divididos em três partes, compilados pelo amigo Gilvan Costa, da CSTHost, tutorial excelente, recomendo.


Instalação do Oracle 11g no Windows 7 - Parte I
Instalação do Oracle 11g no Windows 7 - Parte II
Instalação do Oracle 11g no Windows 7 – Final


Parte 1/3
Parte 2/3
Parte 3/3