SQL complicada. Usando Data

Firebird

12/01/2005

Oi,

Preciso de uma sql que retorne o valor da ultima venda de cada cliente de cada dia.
No access fica assim:

select data, codcli, last(valor) as UltimaVenda
from vendas
where data<date-30
group by data, codcli

Porem no Firebird não existe o ´last´, teria algo semelhente?


:arrow: [color=red:c089737d5b]Título alterado por oTTo. Removido: ´me ajudem´.[/color:c089737d5b]


Larry

Larry

Curtidas 0

Respostas

Emerson Nascimento

Emerson Nascimento

12/01/2005

select data, codcli, max(valor) as UltimaVenda
from vendas
where data<date-30
group by data, codcli


GOSTEI 0
Larry

Larry

12/01/2005

select data, codcli, max(valor) as UltimaVenda from vendas where data<date-30 group by data, codcli


max(valor) irá pegar o maior valor do dia pro cliente, e eu quero o ultimo valor. Tem como?


GOSTEI 0
Thomaz_prg

Thomaz_prg

12/01/2005

colega, não tenho certeza se irá funcionar, mas tente assim:

select data, codcli, (select last 1 valor from vendas b where b.codcli = a.codcli and b.data = a.data) as Ultima_Venda from vendas a where a.data<(select current_date from RDB$Database)-30
group by a.data, a.codcli

Poste aí se deu certo ou não.


GOSTEI 0
Larry

Larry

12/01/2005

colega, não tenho certeza se irá funcionar, mas tente assim: select data, codcli, (select last 1 valor from vendas b where b.codcli = a.codcli and b.data = a.data) as Ultima_Venda from vendas a where a.data<(select current_date from RDB$Database)-30 group by a.data, a.codcli Poste aí se deu certo ou não.


Oi,

Testei on ibexpert e da erro no 1 e se remover o 1, da erro no last. Algo mais?


GOSTEI 0
Afarias

Afarias

12/01/2005

não existe LAST ... existe FIRST (FIREBIRD APENAS!), então faça:


select first 1 valor from vendas
order by data desc


ordenando a data de forma descendente e pegando o 1º registro apenas, vc terá o último registro (na ordem de data)


T+


GOSTEI 0
Fsflorencio

Fsflorencio

12/01/2005

select DISTINCT data, codcli, ( SELECT VALOR FROM VENDAS V1
WHERE V1.COD_VENDA = (SELECT MAX(COD_VENDA) FROM VENDAS V2 WHERE V2.COD_CLI = V.COD_CLI AND V2.DATA = V.DATA) )
from vendas V
where data<date-30

//levando em conta que o código da venda é a chave primária com um número crescente

//tirei o group by pois não uso nenhuma função agregada no select principal, mas coloquei o distinct para não ocorrer repetição

//apelidei as tabelas de vendas como V, V1 e V2

resumo: estou agrupando a data e o código do cliente buscando o maior valor para aquele cliente daquele período, selecionando o maior código de venda daquela data e daquele cliente para buscar o valor da venda do código da venda encontrado


GOSTEI 0
Larry

Larry

12/01/2005

select DISTINCT data, codcli, ( SELECT VALOR FROM VENDAS V1 WHERE V1.COD_VENDA = (SELECT MAX(COD_VENDA) FROM VENDAS V2 WHERE V2.COD_CLI = V.COD_CLI AND V2.DATA = V.DATA) ) from vendas V where data<date-30 //levando em conta que o código da venda é a chave primária com um número crescente //tirei o group by pois não uso nenhuma função agregada no select principal, mas coloquei o distinct para não ocorrer repetição //apelidei as tabelas de vendas como V, V1 e V2 resumo: estou agrupando a data e o código do cliente buscando o maior valor para aquele cliente daquele período, selecionando o maior código de venda daquela data e daquele cliente para buscar o valor da venda do código da venda encontrado


Oi,

Valeu pela força,

Funcionou perfeito, mas ficou muito lento para retornar os resultados quado os periodo (where data...) for muito grande, oque resulta em muitos registros - e são milhares.

Acabei fazendo de outra forma:

select data, codcli, max(cont) as Maior <- chave primaria
from vendas
where data>:d1
group by data, codcli

Então coloquei um campo calculado (valor_calc) que faz um oncalcfiled:
´select valor from vendas where cont = ´+dataset.fieldbyname(´maior´).asstring


Esta é a melhor solução ou tem algo melhor?


GOSTEI 0
Larry

Larry

12/01/2005

não existe LAST ... existe FIRST (FIREBIRD APENAS!), então faça: select first 1 valor from vendas order by data desc ordenando a data de forma descendente e pegando o 1º registro apenas, vc terá o último registro (na ordem de data) T+


Oi, valeu pela ajuda.

Cheguei a pensar nesta solução, mas me preocupei com:
Se eu fizer algo do tipo select valor from vendas where cont = 1500, o firebird valor me retornar apenas 1 registro instantaneamente.
Será que se eu fizer select first 1 from vendas order by data desc, o firebird não vai fazer algo como ´puxar´ todos os registro da tabela para colocar em ordem decrescente para retorna o primeiro registro, oque ficaria lento.
Me aparece que isso ocorre com o comando LIKE e UCASE ???


GOSTEI 0
Larry

Larry

12/01/2005

Outro detalhe, preciso do ultimo valor de cada dia de cada cliente, entao teria que ser algo do tipo:
select data, codcli, first 1 valor
from vendas
group by data, codcli
order by valor desc

Só que este sql não funciona. E ainda o resultado tem que ser em ordem de data crescente.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

12/01/2005

como você informou que [i:2249a0a307]cont[/i:2249a0a307] é a chave primária, veja se assim funciona:

select v.data, v.codcli, v.valor
from vendas v
where v.cont in (select max(v2.cont) from vendas v2
                          where v2.data>:d1
                          group by v2.data, v2.codcli)


GOSTEI 0
Adilsond

Adilsond

12/01/2005

Vamos por partes. Partindo do princípio de que o campo data seja data/hora da venda:

Pegaremos primeiro a maior data/hora de um cliente específico e em um dia específico:

select max(v.data)
from vendas v
where v.codcli = xxxxx
  and cast(v.data as date) = xxxxx


Agora com a data em mãos, pegaremos o maior valor por cliente:

select v1.codcli,
       v1.data,
       v1.valor
from vendas v1
where data = (select max(v2.data)
              from vendas v2
              where v2.codcli = v1.codcli
                and cast(v2.data as date) = cast(v1.data as date))
order by v1.codcli,
         v1.data



GOSTEI 0
Emerson Nascimento

Emerson Nascimento

12/01/2005

então, Larry, a dica que eu te passei

[color=blue:06505f86fe][i:06505f86fe]select v.data, v.codcli, v.valor
from vendas v
where v.cont in (select max(v2.cont) from vendas v2
                          where v2.data>:d1
                          group by v2.data, v2.codcli)
order by v.data[/i:06505f86fe][/color:06505f86fe]

ou a de algum dos colegas funcionou? poste aqui a solução que você encontrou.


GOSTEI 0
Larry

Larry

12/01/2005

então, Larry, a dica que eu te passei [color=blue:bb84a26998][i:bb84a26998]select v.data, v.codcli, v.valor from vendas v where v.cont in (select max(v2.cont) from vendas v2                           where v2.data>:d1                           group by v2.data, v2.codcli) order by v.data[/i:bb84a26998][/color:bb84a26998] ou a de algum dos colegas funcionou? poste aqui a solução que você encontrou.


Valeu pela força Emerson,

Funcionou perfeito, mas acabou ficando lento tambem quando o periodo for grande, oque retorna muitos (milhares) de registros.
Até agora a forma mais rapida é a que fiz:

select data, codcli, max(cont) as Maior <- chave primaria
from vendas
where data>:d1
group by data, codcli

Então coloquei um campo calculado (valor_calc) que faz um oncalcfiled:
´select valor from vendas where cont = ´+dataset.fieldbyname(´maior´).asstring

Oque eu fiz é mais ou menos a mesma coisa que voce sugeriu, mas não sei exetamente porque, mas do jeito que eu fiz fica bem mais rapido.

Me parece que o trecho que voce sugeriu:
where v.cont in (select max(v2.cont) from vendas v2
where v2.data>:d1
group by v2.data, v2.codcli)
o firebird torna muito lento, ou até o firebird executa este segundo select da clausula where para cada registro do primeiro select -> não acredito que o firebird faça isso, mas porque a tamanha lentidão?.
Sempre que eu coloquei selects dentro da clausula where tive problemas com lentidão.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

12/01/2005

para funcionar bem, você precisa de um índice para o campo [u:e41d8e688b]vcont[/u:e41d8e688b] (creio que já exista, pois você afirmou que esse campo é a chave primária) e um outro índice para os campos [i:e41d8e688b]data[/i:e41d8e688b] e [i:e41d8e688b]codcli[/i:e41d8e688b]. você os tem?


GOSTEI 0
Larry

Larry

12/01/2005

para funcionar bem, você precisa de um índice para o campo [u:dfe1acc32e]vcont[/u:dfe1acc32e] (creio que já exista, pois você afirmou que esse campo é a chave primária) e um outro índice para os campos [i:dfe1acc32e]data[/i:dfe1acc32e] e [i:dfe1acc32e]codcli[/i:dfe1acc32e]. você os tem?


Oi,

Os tres campos ja tem indice.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

12/01/2005

o group by precisa de um índice pelos dois campos. deveria ser algo assim

Indice1 - cont
Indice2 - data, codcli


GOSTEI 0
Larry

Larry

12/01/2005

o group by precisa de um índice pelos dois campos. deveria ser algo assim Indice1 - cont Indice2 - data, codcli


Oi,

Peguei o problema:
O campo data é do tipo timestamp (data+hora), então criei um campo Data1 com ´computed by cast(data as date)´ e assim tava lento.
Agora criei um campo Data2 do tipo date, transferi as informações do campo Data1 e criei os indices. Ai sim ficou muito mais rapido.

Valeu.


GOSTEI 0
POSTAR