Tratar dados do BD [RESOLVIDO]

16 respostas
P

Pessoal,

tenho que fazer uma consulta no BD e o retorno tenho que separar por períodos, mas o que define estes períodos são as mensagens de inicio, meio e fim, onde tenho que pegar valores dentro destes períodos e calcular média, e saber quantos inicio, meio e fim, teve naquela consulta:

Fiz esse script:

select * from tb_telemetria where id_ult_mensagem in ('inicio','meio','final') and cod_dispositivo = 'QAG0034306' and cod_usuario = 6 AND to_char( dt_hora_sistema, 'DD/MM/YYYY') BETWEEN ('07/09/2014') AND ('30/10/2014') AND to_char( dt_hora_sistema, 'HH24:MI') BETWEEN ('00:00') AND ('22:22') order by dt_hora_sistema;

Assim esta trazendo tudo dentro das datas… mas o que preciso fazer:

1º - saber quantos trios veio nesse período (inicio, meio e fim, tipo é uma viagem, então quantas viagens fez?)

2º - Por exemplo, deu 3 viagens, em cada viagem, eu pego os valores de inicio até o final e faço a média de um campo

Exemplo:

1ª viagem:

inicio (começo a pegar o valor do campo)

meio (vou pegando o valor)

meio (vou pegando o valor)

final (mostro a media)

2ª viagem:

inicio (começo a pegar o valor do campo)

meio (vou pegando o valor)

meio (vou pegando o valor)

final (mostro a media)

E caso a 3ª viagem não estiver completa por causa do período, eu não mostro

Dados do BD:

char integer varchar varchar timestamp without dispositivo usuario campo mensagem data "QAG0034306"; 6; " "; "INICIO"; "1969-12-31 17:59:59" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 08:44:29" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 08:44:59" "QAG0034306"; 6; "11."; "MEIO"; "2014-10-08 08:45:29" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 08:45:59" "QAG0034306"; 6; "5.7"; "MEIO"; "2014-10-08 08:46:29" "QAG0034306"; 6; "6.3"; "MEIO"; "2014-10-08 08:46:59" "QAG0034306"; 6; "9.2"; "MEIO"; "2014-10-08 08:47:29" "QAG0034306"; 6; "25.2"; "MEIO"; "2014-10-08 08:47:59" "QAG0034306"; 6; "25.2"; "MEIO"; "2014-10-08 08:48:29" "QAG0034306"; 6; "25.2"; "FINAL"; "1969-12-31 17:59:59" "QAG0034306"; 6; " "; "INICIO"; "1969-12-31 17:59:59" "QAG0034306"; 6; " "; "MEIO"; "2014-10-08 09:04:38" "QAG0034306"; 6; " "; "MEIO"; "2014-10-08 09:05:08" "QAG0034306"; 6; "13.6"; "MEIO"; "2014-10-08 09:05:38" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 09:06:08" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 09:06:38" "QAG0034306"; 6; "Inf"; "MEIO"; "2014-10-08 09:07:08" "QAG0034306"; 6; "17.3"; "MEIO"; "2014-10-08 09:07:38" "QAG0034306"; 6; "12.8"; "MEIO"; "2014-10-08 09:08:08" "QAG0034306"; 6; "5.5"; "MEIO"; "2014-10-08 09:08:38" "QAG0034306"; 6; "39.8"; "MEIO"; "2014-10-08 09:09:38" "QAG0034306"; 6; "39.8"; "FINAL"; "1969-12-31 17:59:59"

16 Respostas

Luiz_Augusto_Prado

Blz?
Cara, não entendi o que quer.
Tem como falar mais pra que serviria isso?

P

eu dei uma adiantada e vou tratar algumas coisas na aplicação, o que está me deixando de cabelo em pé é a consulta no BD

Quando vem a mensagem de inicio e fim, ele vem com data zuada, (tipo ano de 1969) só que como eu consulto por período, ele não traz as mensagens de início e fim, pensei em fazer algo assim:

IF id_ult_mensagem = 'inicio' OR id_ult_mensagem = 'final' THEN AND to_char( dt_hora_dispositivo, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_dispositivo, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') ELSE AND to_char( dt_hora_sistema, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_sistema, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') END IF

pois tenho essa data do sistema tbm, mas não é correto eu usar ela…

Mas não sei a sintaxe correta para utilizar, estou lendo a documentação ainda…

Minha necessidade é fazer uma consulta no BD, pegar o resultado e ver quantas viagens aconteceram, que definirei pelas mensages de inicio, meio e fim…

Ai tenho que saber quantas dessas viagens “fechadas (com inicio, meio e fim)” tem naquele período consultado

B

Não entendi muito bem…
Me parece que você quer trazer três informações em intervalos de datas, é isso?
Se for isso, como cada tipo de informação pode ter algum parâmetro diferente na clausula WHERE, considere utilizar junção vertical da consulta.
ex:

select * from tabela1 WHERE id_ult_mensagem = 'inicio' and data between 'data1' and 'data2'
union (ou union all)
select * from tabela1 WHERE id_ult_mensagem = 'meio' and data between 'data1' and 'data2'
union (ou union all)
select * from tabela1 WHERE id_ult_mensagem = 'final' and data between 'data1' and 'data2'

Cada clausula WHERE pode ser colocado os parametros que você quer para cada tipo de mensagem. Ficar atento para as colunas que vão ser retornadas em cada consulta. Elas tem que ter a mesma quantidade de colunas e serem do mesmo tipo.

Se não for útil, desconsidere o post.

P

oi amigo, não é isso que quero, vou tentar explicar melhor…

recebo dados de um dispositivo, a situação é uma viagem… eu tenho que fazer uma consulta, e verificar quantas viagens fechadas tem (com início, meio e fim)… e tenho que validar por estas mensagens que identificam se é inicio meio e fim, os dados vem assim:

inicio
meio - N vezes (podendo se repetir até acabar a viagem)
fim

ai pego um bloco, podendo ter várias viagens…

só que o meu problema é que consulto por período de data (por exemplo 06/11/2014 08:00 às 06/11/2014 08:10)… MAS… as mensagens de inicio e fim vem com data errada, por exemplo:

inicio (“1969-12-31 17:59:59”)
meio (“06/11/2014 08:05”)
meio (“06/11/2014 08:06”)
meio (“06/11/2014 08:07”)
meio (“06/11/2014 08:08”)
meio (“06/11/2014 08:09”)
fim (“1969-12-31 17:59:59”)

Então não estou conseguindo pegar as mensagens de inicio e fim pq estão fora do período de busca (data errada)

só que tem outra data que posso usar (não é a melhor mas tem tbm) então pensei em fazer um IF (caso seja mensagem de inicio ou fim, usar a data do sistema)

Mas não sei a sintaxe correta…

B

Então…
Como te falei ali em cima, você pode pode utilizar a versão vertical para a situação ali quando a data está errada, como foi mencionado. Com isso, você pode trabalhar com várias consultas e diferentes clausulas WHERE’s pra poder fazer a consulta.

B

Mais ou menos assim:

select * from tabela1 WHERE id_ult_mensagem in ( 'inicio', 'final') and dt_hora_sistema between 'data1' and 'data2'
union all
select * from tabela2 WHERE id_ult_mensagem = 'meio' and dt_hora_sistema between 'data1' and 'data2'

Ficaria mais ou menos assim pra você consultar duas informações com datas diferentes, porém. Você pode usar funções de grupo, como desejar.
Mas ficar atento que a segunda consulta tem que retornar a mesma quantidade de linhas que a primeira, e ser dos mesmos tipos.

B

Outra solução, é você usar ‘CASE WHEN’ pra fazer a consulta por datas diferentes na clausula WHERE.

select * 
      from tabela1
  WHERE (CASE WHEN id_tp_mensagem = 'MEIO' THEN 'informar intervalor de datas aqui' ELSE 'informar o outro intervalo de datas aqui' END);
P

Consegui… mas da um erro de ordenação ainda… .não sei se é pq estou tratando as datas como string…

“2014-09-30 17:32:20”
“2014-09-30 17:32:50”
“2014-10-01 15:10:58”
“2014-10-01 20:17:03”
“2014-10-01 21:56:15”
“2014-10-01 16:47:53”
“2014-10-01 20:17:32”
“2014-10-01 21:56:45”
“2014-10-02 08:37:57”
“2014-10-02 10:23:09”
“2014-10-01 16:48:23”
“2014-10-01 20:18:02”
“2014-10-01 21:57:15”

SELECT * FROM tb_telemetria INNER JOIN tb_usuario ON tb_usuario.cod_usuario = tb_telemetria.cod_usuario INNER JOIN tb_veiculo ON tb_veiculo.id_veiculo = tb_telemetria.id_veiculo AND tb_usuario.cod_usuario = tb_veiculo.cod_usuario WHERE (CASE WHEN id_ult_mensagem = 'meio' THEN to_char( dt_hora_dispositivo, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_dispositivo, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') ELSE to_char( dt_hora_sistema, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_sistema, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') END) AND tb_veiculo.num_chassi = '9BGRP48F0EG236318' AND tb_usuario.desc_login = 'ped6' AND id_ult_mensagem IN ('inicio','meio','fim')

B

Não precisa usar o to_char pra fazer o between entre as datas e horários. Pode usar direto ‘2014-01-01 23:00’, por exemplo.
E pra ordenar a saída, não vi nenhuma cláusula de ordenação, no caso o ORDR BY.

No final da consulta, pode fazer assim

ORDER BY coluna; (crescente)
ou
ORDER BY coluna DESC; (DECRESCENTE)

Outra coisa, você precisa trazer os dados das 3 tabelas na sua consulta? Tente trazer somente o que é necessário, pois se a consulta não for filtrada corretamente, pode demorar muito e ter perda de performance.

P

o filtro vou fazer depois… primeiro quero ver se funciona a lógica…

é que o campo é timestamp, mas os dados vem como string… e nessa formatação…

mesmo eu colocando order by… ele traz primeiro outubro começando crescente (1, 2, 3,…) e no último dia de outubro começa setembro (28, 29, 30…) por isso não sei se é pq está como to_char …

B

Tenta converter pra date ou timestamp e ordenar…

select '2014-01-01'::date
P

bomba, muito obrigado… funcionou tirando os INNER JOIN…

SELECT * FROM tb_telemetria, tb_usuario, tb_veiculo WHERE (CASE WHEN id_ult_mensagem = 'meio' THEN to_char( dt_hora_dispositivo, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_dispositivo, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') ELSE to_char( dt_hora_sistema, 'DD/MM/YYYY') BETWEEN ('01/10/2014') AND ('30/10/2014') AND to_char( dt_hora_sistema, 'HH24:MI') BETWEEN ('00:00') AND ('23:59') END) AND tb_usuario.cod_usuario = tb_telemetria.cod_usuario AND tb_usuario.cod_usuario = tb_veiculo.cod_usuario AND tb_veiculo.num_chassi = '9BGRP48F0EG236318' AND tb_usuario.desc_login = 'ped6' AND id_ult_mensagem IN ('inicio','meio','fim') ORDER BY tb_telemetria.dt_hora_sistema

só que fiquei curioso com seu conversor… se puder me ensinar a converter para timestamp (no where) eu agradeço… mas resolveu meu problema… muito obrigado

B

Na verdade, o padrão SQL (que eu conheço), as junções horizontais são feitas com JOINS.
Existem vários tipos, porém, os mais utilizados são INNER (join), LEFT OUTER JOIN e RIGHT JOIN.

Inner join: Faz junção de duas tabelas onde a informação realmente exista nos dois lados.
left outer join: traz os dados da tabela da esquerda, se o mesmo não estiver na tabela da direita.
right join: Traz os dados da tabela da direita, se o mesmo não não estiver na tabela da esquerda.

O conversor funciona tanto na clausula do select, tanto na clausula WHERE.

No post anterior eu me enganei quanto ao conversor com hora. O tipo date só trabalha com data, o timestamp com data + horário, então o correto seria converter pra timestamp.

Façao seguinte teste:

select '2014-01-01 23:00:01'::timestamp > '2014-01-01 23:00:00'::timestamp

Note que o retorno vai ser TRUE, porque realmente, a primeira condição é maior que a segunda. Dessa maneira, você pode converter e ordenar a coluna.

P

Valeu cara…

Uma última dúvida…

Teria como eu colocar um apelido na data? tipo para pegar a data que eu estou usando?
se vier a do sistema ou do dispositivo eu usar um alias para definir sempre um só campo? para usar na aplicação?

B

Pra colocar um alias, basta fazer assim:

select coluna AS meu_apelido
ou 
select coluna meu_apelido

Dessa forma, você pode repetir as colunas e dar apelidos diferentes pra ela.

O recurso de alias (apelido), funciona tanto para colunas quanto para tabelas. Exemplo:

select a.coluna, b.coluna1
 FROM tabela1 as A
 JOIN tabela2 as b on (a.coluna = b.coluna)
P

entendi… mas no meu caso, onde trato as datas… teria como?

se usei o dt_hora_dispositivo ou o dt_hora_sistema AS data ?

Pois este if está no where

Criado 29 de outubro de 2014
Ultima resposta 6 de nov. de 2014
Respostas 16
Participantes 3