UPDATE - Subtracao de campos entre duas tabelas

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
andremeiras
Rank: Estagiário Júnior
Rank: Estagiário Júnior
Mensagens: 2
Registrado em: Qua, 27 Jun 2012 8:27 pm

Ola, bom dia.

Primeiramente gostaria de agradecer ao admin por me acc aqui no forum e ao mesmo tempo parabenizar a todos os membros deste forum pelos posts.

Como sou novo aqui no forum não tenho certeza se este é o lugar certo para postar minha duvida.
Se eu estiver postando no lugar errado, me desculpem.

Estou com uma duvida sobre UPDATE.

Eu tenho uma tabela chamada TRANSACAO e outra CCA (ContaClienteAgencia) como podem ver abaixo.

Selecionar tudo

SQL> desc transacao
 Nome                                      Nulo?    Tipo
 ----------------------------------------- -------- -------------

 CPF                                       NOT NULL NUMBER(11)
 NUM_AG                                    NOT NULL NUMBER(3)
 NUM_CONTA                                 NOT NULL NUMBER(6)
 ID_TRANS                                  NOT NULL NUMBER(3)
 TIPO                                      NOT NULL NUMBER(3)
 DATA                                      NOT NULL TIMESTAMP(6)
 QUANTIA                                            FLOAT(126)

SQL> DESC CCA
 Nome                                      Nulo?    Tipo
 ----------------------------------------- -------- -------------

 CPF                                       NOT NULL NUMBER(11)
 NUM_AG                                    NOT NULL NUMBER(3)
 NUM_CONTA                                 NOT NULL NUMBER(6)
 SALDO                                     NOT NULL FLOAT(126)
Eu preciso fazer um UPDATE do SALDO da tabela CCA onde sera efetuado um calculo da QUANTIA da tabela TRANSACAO.

Este é um exercicio de um trabalho de uma instituicao financeira (banco).

já pesquisei, tentei fazer com o pouco conhecimento que tenho, mas não consigo sair do lugar. :?

Se alguém puder me ajudar, fico muito grato. :-o

Abracos a todos.
RodrigoValentim
Moderador
Moderador
Mensagens: 367
Registrado em: Ter, 25 Mar 2008 3:41 pm
Localização: Salvador - BA
Rodrigo Valentim
Analista de Sistemas
Oracle Developer

Campanha: Faça uma pesquisa antes de perguntar!!!

Você quer alterar o campo SALDO da tabela CCA com o total da soma da tabela transacao ?
ou você quer isso por registro?

o update seria trabalhado com base no CPF que aparenta ser a PK

você pode fazer isso de 2 formas (podem existir outras)

PL/SQL ou SQL PURO

Selecionar tudo


UPDATE CCA C 
      SET SALDO = (SELECT SUM(QUANTIA) 
                             FROM TRANSACAO T 
                           WHERE T.CPF = C.CPF
                                AND T.NUM_AG = C.NUM_AG
                                AND T.NUM_CONTA = C.NUM_CONTA) WHERE C.CPF = XXXXXXXXXXXX

Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Assumindo que você queira criar um programa que faça uma transação refletir o novo saldo na tabela CCA, você precisa "incrementar" ou "decrementar" a quantia inserida no campo saldo da tabela existente. Ou seja: inserir se for a primeira vez, ou update se a linha já existir.

Agora como evitar que a tabela CCA fique com saldos inconsistentes... um jeito é revogar privilégios de insert/update/delete (qualquer DML) nas tabela CCA e TRANSACAO, permitindo que apenas a aplicação autorizada a fazer isso seja uma API contendo a transação (insere em Transação e atualiza CCA em conjunto).

Pode ser tentador fazer isso por trigger, mas eu não gosto da ideia de usar trigger para isso, pois oculta a lógica e dificulta muito a manutenção futura, além de ser altamente vulnerável a bugs; o que deixaria sua tabela CCA propensa a ficar inconsistente.

Segue um exemplo de uma maneira de fazer isso por package:

Selecionar tudo

SQL> CREATE TABLE transacao (
  2  CPF                                       NUMBER(11) NOT NULL ,
  3  NUM_AG                                    NUMBER(3) NOT NULL ,
  4  NUM_CONTA                                 NUMBER(6) NOT NULL ,
  5  ID_TRANS                                  NUMBER(3) NOT NULL ,
  6  TIPO                                      NUMBER(3) NOT NULL,
  7  DATA                                      TIMESTAMP(6) NOT NULL ,
  8  QUANTIA                                   FLOAT(126));
 
Table created
SQL> CREATE TABLE CCA (
  2  CPF                                       NUMBER(11) NOT NULL ,
  3  NUM_AG                                    NUMBER(3) NOT NULL ,
  4  NUM_CONTA                                 NUMBER(6) NOT NULL ,
  5  SALDO                                     FLOAT(126) NOT NULL);
 
Table created
SQL> CREATE SEQUENCE SQ_ID_TRANS START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
 
Sequence created
SQL> create or replace package pk_movimenta_conta as
  2  
  3    procedure registra_transacao (p_CPF       IN transacao.cpf%type,
  4                                  p_NUM_AG    IN transacao.num_ag%type,
  5                                  p_NUM_CONTA IN transacao.num_conta%type,
  6                                  p_TIPO      IN transacao.tipo%type,
  7                                  p_DATA      IN transacao.data%type,
  8                                  p_QUANTIA   IN transacao.quantia%type,
  9                                  p_ID_TRANS  OUT transacao.id_trans%type);
 10  
 11  end pk_movimenta_conta;
 12  /
 
Package created
SQL> create or replace package body pk_movimenta_conta as
  2  
  3  
  4    procedure registra_transacao (p_CPF       IN transacao.cpf%type,
  5                                  p_NUM_AG    IN transacao.num_ag%type,
  6                                  p_NUM_CONTA IN transacao.num_conta%type,
  7                                  p_TIPO      IN transacao.tipo%type,
  8                                  p_DATA      IN transacao.data%type,
  9                                  p_QUANTIA   IN transacao.quantia%type,
 10                                  p_ID_TRANS  OUT transacao.id_trans%type) is
 11    begin
 12      select sq_id_trans.nextval into p_id_trans from dual;
 13      insert into transacao (CPF      ,
 14                             NUM_AG   ,
 15                             NUM_CONTA,
 16                             ID_TRANS ,
 17                             TIPO     ,
 18                             DATA     ,
 19                             QUANTIA  )
 20        values (p_CPF      ,
 21                p_NUM_AG   ,
 22                p_NUM_CONTA,
 23                p_ID_TRANS ,
 24                p_TIPO     ,
 25                p_DATA     ,
 26                p_QUANTIA  );
 27  
 28      merge into cca c
 29        using (select cpf, num_ag, num_conta, quantia
 30                 from transacao
 31                where id_trans = p_id_trans) t
 32        on (c.cpf = t.cpf and c.num_ag = t.num_ag and c.num_conta = t.num_conta)
 33        when matched then
 34          update set c.saldo = c.saldo + p_quantia
 35        when not matched then
 36          insert (c.cpf, c.num_ag, c.num_conta, c.saldo)
 37          values (p_cpf, p_num_ag, p_num_conta, p_quantia);
 38    end;
 39  
 40  end pk_movimenta_conta;
 41  /
 
Package body created
SQL> DECLARE
  2    v_id_trans NUMBER;
  3  BEGIN
  4    -- registra transação na primeira conta (insere)
  5    pk_movimenta_conta.registra_transacao(p_cpf => 00012345678,
  6                                          p_num_ag => 1,
  7                                          p_num_conta => 9999,
  8                                          p_tipo => 3,
  9                                          p_DATA => trunc(SYSDATE),
 10                                          p_quantia => 1000.00,
 11                                          p_id_trans => v_id_trans);
 12    -- registra transação na primeira conta (atualiza)
 13    pk_movimenta_conta.registra_transacao(p_cpf => 00012345678,
 14                                          p_num_ag => 1,
 15                                          p_num_conta => 9999,
 16                                          p_tipo => 3,
 17                                          p_DATA => trunc(SYSDATE),
 18                                          p_quantia => 1000.00,
 19                                          p_id_trans => v_id_trans);
 20    -- registra transação na segunda conta (insere)
 21    pk_movimenta_conta.registra_transacao(p_cpf => 333,
 22                                          p_num_ag => 1,
 23                                          p_num_conta => 9990,
 24                                          p_tipo => 3,
 25                                          p_DATA => trunc(SYSDATE),
 26                                          p_quantia => 5000.00,
 27                                          p_id_trans => v_id_trans);
 28    -- registra transação na segunda conta (atualiza)
 29    pk_movimenta_conta.registra_transacao(p_cpf => 333,
 30                                          p_num_ag => 1,
 31                                          p_num_conta => 9990,
 32                                          p_tipo => 3,
 33                                          p_DATA => trunc(SYSDATE),
 34                                          p_quantia => 5000.00,
 35                                          p_id_trans => v_id_trans);
 36  END;
 37  /
 
PL/SQL procedure successfully completed
SQL> select * from transacao;
 
         CPF NUM_AG NUM_CONTA ID_TRANS TIPO DATA                                                                                                                       QUANTIA
------------ ------ --------- -------- ---- ------------------------------------------------- --------------------------------------------------------------------------------
    12345678      1      9999        1    3 28/06/12 00:00:00,000000                                                                                                      1000
    12345678      1      9999        2    3 28/06/12 00:00:00,000000                                                                                                      1000
         333      1      9990        3    3 28/06/12 00:00:00,000000                                                                                                      5000
         333      1      9990        4    3 28/06/12 00:00:00,000000                                                                                                      5000
SQL> select * from cca;
 
         CPF NUM_AG NUM_CONTA                                                                            SALDO
------------ ------ --------- --------------------------------------------------------------------------------
    12345678      1      9999                                                                             2000
         333      1      9990                                                                            10000
SQL> drop table transacao;
 
Table dropped
SQL> drop table cca;
 
Table dropped
SQL> drop sequence sq_id_trans;
 
Sequence dropped
SQL> drop package pk_movimenta_conta;
 
Package dropped
 
SQL> 
Lembro que é extremamente importante tirar os grants de insert/update/delete nas tabelas, para impedir outras aplicações e usuários de manipulá-las sem respeitar a lógica da transação.
andremeiras
Rank: Estagiário Júnior
Rank: Estagiário Júnior
Mensagens: 2
Registrado em: Qua, 27 Jun 2012 8:27 pm

RodrigoValentim escreveu:Você quer alterar o campo SALDO da tabela CCA com o total da soma da tabela transacao ?
ou você quer isso por registro?

o update seria trabalhado com base no CPF que aparenta ser a PK

você pode fazer isso de 2 formas (podem existir outras)

PL/SQL ou SQL PURO

Selecionar tudo


UPDATE CCA C 
      SET SALDO = (SELECT SUM(QUANTIA) 
                             FROM TRANSACAO T 
                           WHERE T.CPF = C.CPF
                                AND T.NUM_AG = C.NUM_AG
                                AND T.NUM_CONTA = C.NUM_CONTA) WHERE C.CPF = XXXXXXXXXXXX

Isso mesmo RodrigoValentim, eu preciso por registro.

Imagina sua conta bancaria.

Supondo que você tenha de SALDO R$ 1000,00 e fez uma TRANSACAO de saque onde você retirou uma QUANTIA de R$ 200,00.
Agora você, como um bom DBA, conseguiu finalizar o trabalho que um outro DBA não conseguiu antes, por preguica, ou desleixo mesmo. Por esse trabalho você recebeu R$ 4800,00 que foi depositado diretamente em sua conta, ou seja, mais uma TRANSACAO mas agora de CREDITO (foi creditado na sua conta).
Somando essas duas operacoes/transacoes você teria no campo SALDO da tabela CCA uma quantia de R$ 5600,00.

Entendeu? Assim por diante para outros registros (NUM_CONTA ou CPF).

Sou aprendiz ainda em SQL e Databases como um todo.
Estou agora, terminando o primeiro periodo de Analise de Sistemas e não sei muito.
Desculpe se eu estiver dizendo alguma besteira, e ate gostaria que me corrigissem.

Muito obrigado pela sua resposta e a do fsitja. Eu não esperava tanta agilidade.

Valeu mesmo.
Responder
  • Informação