Comando SUM

Fórum sobre a linguagem CA-Clipper.

Moderador: Moderadores

Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Comando SUM

Mensagem por Pablo César »

Em resposta ao colega Carvalho.
Em 31 Mar 2014 14:17, por MP, Carvalho escreveu:ola.
Tenho um arquivo com apenas dois campos numa base de dados que se chama Leite.dbf
os campos sao:
Data
Quant

Refere-se ao controle diario de retirada de leite de uma fazenda. Coloca a data do dia, e a quantidade de leite.
Agora preciso criar uma consulta entre duas datas, para saber a quantidade de leite tirada entre essas determinadas datas. ex: quanto foi o acumulado de leite entre os dias 01/02/2014 e 28/02/2014.
Sei que a funcao SUM faz a soma, mas nao sei como filtrar entre duas datas. poderia me dar uma dica ?
Vejamos primeiramente a sintaxe do comando SUM:
SUM
Soma expressoes numéricas e coloca o valor em variáveis
───────────────────────────────────────────────────────
Sintaxe

SUM <nLista expr> TO <idLista var>
[<abrangência>] [WHILE <lCondiçao>] [FOR <lCondiçao>]

Argumentos

<nLista expr> é a lista de valores numéricos a serem somados para
cada registro processado.

<idLista var> identifica as variáveis receptoras da soma.
Variáveis que nao existam ou nao sejam visíveis sao criadas como
privadas. <idList var> deve conter o mesmo número de elementos de
<nLista expr>.

<abrangência> é a porçao do arquivo de dados a ser somada (SUM). O
assumido é todos (ALL).

WHILE <lCondiçao> especifica o conjunto de registros a partir do
registro corrente até que a condiçao seja falsa.

FOR <lCondiçao> especifica o conjunto condicional de registros a
serem somados dentro da abrangência dada.

Descriçao

SUM soma uma série de expressoes numéricas e armazena o resultado em
variáveis para uma faixa de registros na área corrente.

Note que <nLista expr> é necessária e nao opcional como em outros
dialetos.

Exemplos

O exemplo seguinte ilustra o uso de SUM:

USE Sales NEW
SUM Price * .10, Amount TO nSum1, nSum2

? nSum1 // Resulta: 151515.00
? nSum2 // Resulta: 150675.00
Para pode somar um período de data, no seu exemplo fariamos assim:

Código: Selecionar todos

Set Date to British
Set Century On
dDta1=Ctod("01/02/2014")
dDta2=Ctod("28/02/2014")
SUM ALL Quant TO nTotal FOR Data>=dDta1 .AND. Data<=dDta2
? nTotal
Uma vez que você captou em duas variáveis através de dois GETs e se o campo Data for do tipo DATA, irá funcionar. Mas da próxima vez tente não colocar nome de campo com a nomenclatura "DATA". Seja bem vindo ao fórum e não fique acanhado de fazer as suas perguntas aqui no fórum (em público).
:)
Espero que consiga visualizar a lógica.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Comando SUM

Mensagem por fladimir »

Pra efeito de conhecimento segue o mesmo resultado porém usando ao invés do comando SUM a função DBEVAL()

Código: Selecionar todos

Set Date to British
Set Century On
dDta1=Ctod("01/02/2014")
dDta2=Ctod("28/02/2014")

/*  Abaixo usaremos a função DBEVAL() no lugar do SUM.
     A sintaxe é a seguinte:
     DbEval( <bBlock>          , ;
                 [<bForCondition>]  , ;
                 [<bWhileCondition>], ;
                 [<nNextRecords>]   , ;
                 [<nRecord>]        , ;
                 [<lRest>]            ) --> NIL


    O primeiro bloco de códigos (bBlock) é o q vc quer fazer, no caso somar o Campo Quant e Armazenar na variável nTotal,  
    o segundo bloco de código (bForCondition) refere-se a condição de filtragem tipo o FOR do SUM.
    Veja a linha abaixo representa o q seria feito com SUM mas usando-se o DBEVAL.
  */ 

DBEVAL(  { ||  nTotal += Quant },  {  || Data>=dDta1 .AND. Data<=dDta2 }  )  

? nTotal
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Comando SUM

Mensagem por alxsts »

Olá!

É sempre bom pensarmos em otimizar nossas aplicações para que tenham a melhor performance possível.

Quando a cláusula ou parâmetro FOR são usados, força-se a leitura da tabela desde o registro onde o ponteiro estiver posicionado até o final da mesma, avaliando a condição para cada registro lido.

Diferentemente disso, quando se usa a cláusula ou parâmetro WHILE, somente os registros, a partir da posição do ponteiro, onde a condição for verdadeira serão avaliados.

Assim, desde que a tabela seja indexada pelo campo critério da seleção, o ideal é posicionar o ponteiro no primeiro registro que atenda o critério e aplicar a condição enquanto ela for verdadeira.

Código: Selecionar todos

Set Date to British
Set Century On
dDta1=Ctod("01/02/2014")
dDta2=Ctod("28/02/2014")

/* Abaixo usaremos a função DBEVAL() no lugar do SUM.
  A sintaxe é a seguinte:
  DbEval( <bBlock>     , ;
        [<bForCondition>] , ;
        [<bWhileCondition>], ;
        [<nNextRecords>] , ;
        [<nRecord>]    , ;
        [<lRest>]      ) --> NIL


  O primeiro bloco de códigos (bBlock) é o q vc quer fazer, no caso somar o Campo Quant e Armazenar na variável nTotal, 
  o segundo bloco de código (bForCondition) refere-se a condição de filtragem tipo o FOR do SUM.
  Veja a linha abaixo representa o q seria feito com SUM mas usando-se o DBEVAL.
 */ 

Use Tabela Shared New

Set Index to idxData   // indexado por ordem de data inicial ===> Index On DtoS( dataIni ) To idxData

nTotal := 0.00

If DbSeek( DtoS( dDta1 ) )

   DBEVAL( { || nTotal += Quant }, NIL, { || Data>=dDta1 .AND. Data<=dDta2 } )  // notar que o segundo parâmetro ([<bForCondition>]) está com NIL 

Endif

? nTotal
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Comando SUM

Mensagem por Pablo César »

Eu tinha pensado indicar algo diferente do que o usuário solicitou. Mas como o DBF parece ser pequeno, se considerar que armazena por ano todos os dias do ano, o SUM não iria ficar pesado. Mas se o arquivo for crescer e acumular vários anos e estes registros precisarão ser processados, isto é, com data muito retroativas, então a sugestão mais indicada seria em indexar o campo DATA em ordem crescente, posicionar-se na primeira data que satisfaz a condição e somar o campo QUANT até que não satisfaça tal condição e sair for do laço de repetição (Do While).
Exemplo:

Código: Selecionar todos

Set Date to British
Set Century On
dDta1=Ctod("01/02/2014")
dDta2=Ctod("28/02/2014")

Use Leite Shared New
If .not. File("PorDta.Ntx")
   Index on DtoS(DATA) to PorDta
Endif
Set Index to PorDta
nTotal := 0.00
DbSeek( DtoS( dDta1 ), .T. )
Do While Data>=dDta1 .AND. Data<=dDta2
   nTotal:=nTotal+QUANT
   Skip
Enddo
? nTotal
Neste meu novo exemplo, não irá percorrer todos os registros como foi pelo comando SUM, apenas processará os registros em questão. Mas atenção o arquivo de índices, precisará estar sempre atualizado.

Fiz da forma menos sintética para que usuários iniciantes, tenham a oportunidade de entender a lógica.

Alexandre, o seu exemplo precisaria considerar que a DATA não sempre poderá ser sequencial. Isto é, se não achar a data seja por feriado ou dia não laborável ou neste caso: dia que não foi extraído o leite ou não registrado. O seu Seek não achará e dará valor zero. Por isso, deveria utilizar o lSoftSeek como verdadeiro (segundo parâmetro do DbSeek). Mas valeu a sua dica de processar apenas os registros em questão e não todos, claro se o banco de dados for grande.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Comando SUM

Mensagem por fladimir »

Pábulo não entendi o ultimo jeito q vc colocou não seria o mesmo do alexandre?
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Comando SUM

Mensagem por Pablo César »

Oi fladimir. Não é o mesmo, note que na linha 12 estou usando com a opção de SoftSeek e sem a condição de que tenha sido encontrado exatamente na mesma data.

DbSeek( DtoS( dDta1 ), .T. )

Assim irá posicionar-se na primeira data maior que a data inicial em pesquisa.

E ainda fiz de forma mais extensa para ajudar o entendimento de iniciantes. Visto que o colega teve dificuldades em entender o SUM.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Comando SUM

Mensagem por alxsts »

Olá!
Pablo César escreveu:DbSeek( DtoS( dDta1 ), .T. )
Perfeito, bem lembrado. Acho que assim tudo fica resolvido. Poderia até simplificar

Código: Selecionar todos

Data>=dDta1 .AND. Data<=dDta2
por

Código: Selecionar todos

Data<=dDta2
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Comando SUM

Mensagem por Pablo César »

Isso ai, Alexandre.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
carvalho
Usuário Nível 1
Usuário Nível 1
Mensagens: 2
Registrado em: 30 Mar 2014 13:10
Localização: Novo Cruzeiro/MG

Comando SUM

Mensagem por carvalho »

Ola amigo,
muito obrigado pelas dicas. Fucionou perfeitamente, so que tive que tirar
os comandos Set Date British e Set Century On.
Porque com eles, o resultado saia sempre zerado, no caso de deixar só o Set Date British, ele retornava
apenas o campo referente a quant da dat1. Mas ta funcionado beleza. Grato pelo Help.
carvalho
Usuário Nível 1
Usuário Nível 1
Mensagens: 2
Registrado em: 30 Mar 2014 13:10
Localização: Novo Cruzeiro/MG

Comando SUM

Mensagem por carvalho »

Segue o programinha funcionando : sem o Set Date British e Set Century On. Com eles nao retornava os valores.

Clear
use leite
index on data to arqdat
dt1=ctod(space(8))
dt2=ctod(space(8))

do while .t.
@ 10,10 say "Data Inicial..:" get dt1
@ 11,10 say "Data Final...:" get dt2
read

sum all quant to totalquant for data>=dt1 .and. data<=dt2
? "Total no Periodo..:" +str (totalquant)

if lastkey()=27
exit
endif
enddo
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Comando SUM

Mensagem por Pablo César »

Oi Carvalho, fico contente que tenha servido nossas indicações.
carvalho escreveu:so que tive que tirar
os comandos Set Date British e Set Century On.
Porque com eles, o resultado saia sempre zerado
Atenção. Isto deve ser porque não começou a gravar no dbf com os quatro dígitos e ai muitos registros ao invés de gravar 2014 gravou como 1914. Verifique as datas e corrija fisicamente no seu DBF (faça cópia antes). O ideal é trabalhar com SET Century ON.

Outra questão, se você está usando o SUM, não precisa indexar. E acostume-se a indexar somente apenas quando há necessidade de criar o indice, mas se ele está presente em todo o programa, não há necessidade de re-criá-lo e sim mantê-lo atualizado. Sempre aberto em todas as ocasiões que precise escrever no DBF.

Eu colocaria o if lastkey()=27 linha antes do sum all...
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Comando SUM

Mensagem por alxsts »

Olá!

Só para constar, as observações que fiz acima valem também para o caso do SUM. Fazendo um SEEK antes do SUM e usando uma condição WHILE, processará apenas os registros que atendem a condição. As observações sobre FOR valem também.
[]´s
Alexandre Santos (AlxSts)
Responder