Translate

quinta-feira, 20 de março de 2014

PostgreSql - Adicionar um intervalo a uma data / hora

Vamos mostrar neste artigo, como acrescentar um período a uma data. Descrevemos 6 exemplos:

Caso tenha interesse, faça o download do exemplo, ou veja no GitHub.
  • 1º exemplo: mostra como acrescentar um período em dias a uma data.
    São descritas duas soluções para resolver este problema. A primeira utiliza a soma de um número inteiro e a segunda utiliza a soma de um intervalo (interval);
  • 2º exemplo: mostra como acrescentar um período em meses a uma data;
  • 3º exemplo: mostra como acrescentar um período em anos a uma data;
  • 4º exemplo: mostra como acrescentar um período composto (utilizando mais de uma unidade de tempo).
  • 5º exemplo: mostra como acrescentar um período a uma coluna do tipo timestamp (possui data e hora).
  • 6º exemplo: mostra como acrescentar um período armazenado em uma coluna do tipo interval (possui intervalos) a uma coluna do tipo timestamp.
1º Exemplo

Os pacientes recebem os resultados dos exames 3 dias após a data do exame. Devemos exibir as datas de entrega dos resultados dos exames. Para calcularmos as datas de entrega vamos utilizar a tabela "tb_exame_paciente". Veja a tabela na imagem abaixo:


Descrição das colunas
  • paciente_codigo: código do paciente;
  • exame_codigo: código do exame;
  • exame_data: data do exame;
Temos duas formas para resolver este exemplo.

1ª Solução

Para acrescentarmos dias a uma data devemos somar um número inteiro.

data + n

Onde n: número de dias

Para exibir as datas de entrega do exame, vamos executar a consulta abaixo:

SELECT
paciente_codigo,
exame_codigo,
exame_data,
exame_data + 3 AS exame_entrega
FROM tb_exame_paciente;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
paciente_codigo,
exame_codigo,
to_char (exame_data, 'dd/mm/yyyy') AS exame_data,
to_char (exame_data + 3, 'dd/mm/yyyy') AS exame_entrega
FROM tb_exame_paciente;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Caso queira saber mais sobre formatação de data veja o artigo:
PostgreSql - Formatar data

2ª Solução

Podemos somar um intervalo a data.

 data + inverval 'n período '
Onde:
  • inverval: tipo de dado que armazena um intervalo de tempo no PostgreSql;
  • n: valor numérico;
  • período: armazena unidades de medida de tempo. Elas são:
    • year / years: intervalo em anos. Ex.: 1 year, 2 years, 3 years ...
    • month / months / mon / mons: intervalo em meses. Ex.: 1 month, 2 months, 3 months ... Também podemos utilizar a unidade abreviada. Ex.: 1 mon, 2 mons, 3 mons ...
    • day / days: intervalo em dias. Ex.: 1 day, 2 days, 3 days ...
    • hour / hours: intervalo em horas. Ex.: 1 hour, 2 hours, 3 hours ...
    • minute / minutes / min / mins: intervalo em minutos. Ex.: 1 minute, 2 minutes, 3 minutes ... Também podemos utilizar a unidade abreviada. Ex.: 1 min, 2 mins, 3 mins ...
    • second / seconds / sec / secs: intervalo em segundos. Ex.: 1 second, 2 seconds, 3 seconds ... Também podemos utilizar a unidade abreviada. Ex.: 1 sec, 2 secs, 3 secs ...
    • millisecond / millisecond: intervalo em milissegundos. Ex.: 1 millisecond, 2 milliseconds, 3 milliseconds ...
    • microsecond / microseconds: intervalo em microssegundos. Ex.: 1 microsecond, 2 microseconds, 3 microseconds ...

Para resolver este exemplo vamos utilizar a unidade de tempo days, pois queremos acrescentar dias.

Para exibir as datas de entrega dos exame, vamos executar a consulta abaixo:

SELECT
paciente_codigo,
exame_codigo,
exame_data,
exame_data + interval '3 days' AS exame_entrega
FROM tb_exame_paciente;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Perceba que quando adicionamos um intervalo a uma data, será retornado além da data a hora (timestamp).

Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
paciente_codigo,
exame_codigo,
to_char(exame_data, 'dd/mm/yyyy') AS exame_data,
to_char(exame_data + interval 'days' ,'dd/mm/yyyy') AS exame_entrega
FROM tb_exame_paciente;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


2º Exemplo

Os equipamentos de uma fábrica passarão por avaliações a cada 3 meses a partir do início da utilização.
Serão feitas 2 avaliações. Para calcularmos as datas destas avaliações utilizaremos a tabela "tb_equipamentos". Veja a imagem desta tabela a seguir.

Descrição das colunas
  • equipamento_id: identificação do equipamento;
  • data_inicio: data de início da utilização do equipamento;
Solução

Podemos acrescentar um intervalo a data.

 data + inverval 'n período'

Onde:
  • inverval: tipo de dado que armazena um intervalo de tempo no PostgreSql;
  • n: valor numérico
  • período:  armazena a unidade de medida de tempo. Neste caso, vamos utilizar a unidade de tempo months, pois precisamos adicionar meses a coluna data_inicio;
Como a manutenção ocorre a cada 3 meses, a 1ª ocorrerá após 3 meses e a 2ª após 6 meses.
Para exibir as datas de manutenção dos equipamentos executamos a consulta abaixo:

SELECT
equipamento_id,
data_inicio,
data_inicio + interval '3 months' AS pri_manutencao,
data_inicio + interval '6 months' AS seg_manutencao
FROM tb_equipamentos;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
equipamento_id,
to_char(data_inicio, 'dd/mm/yyyy') AS data_inicio,
to_char(data_inicio + interval '3 months', 'dd/mm/yyyy') AS pri_manutencao,
to_char(data_inicio + interval '6 months', 'dd/mm/yyyy') AS seg_manutencao
FROM tb_equipamentos;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.



3º Exemplo

As turmas de uma escola devem fazer 1 teste a cada ano, a partir da data de início das aulas. Serão feitos dois teste. Para calcularmos as datas dos testes utilizaremos a tabela "tb_turma". Veja a imagem desta tabela a seguir.


Descrição das colunas
  • turma_id: identificação da turma;
  • curso_id: identificação do curso;
  • data_inicio: data de início da turma;
Solução

Podemos acrescentar um intervalo a data.

 data + inverval 'n período'

Onde:
  • inverval: tipo de dado que armazena um intervalo de tempo no PostgreSql;
  • n: valor numérico;
  • período: armazena a unidade de medida de tempo. Neste caso, vamos utilizar a unidade de tempo year / years, pois precisamos adicionar anos a coluna data_inicio;
Como o teste é aplicado a cada ano,  o 1º teste ocorrerá após 1 ano e o 2º teste ocorrerá após 2 anos.

Para exibir as datas dos testes executamos a consulta abaixo:

SELECT
turma_id,
curso_id,
data_inicio,
data_inicio + interval '1 year' AS pri_teste,
data_inicio + interval '2 years' AS seg_teste
FROM tb_turma;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
turma_id,
curso_id,
to_char(data_inicio, 'dd/mm/yyyy') AS data_inicio,
to_char(data_inicio + interval '1 year',  'dd/mm/yyyy') AS pri_teste,
to_char(data_inicio + interval '2 years', 'dd/mm/yyyy') AS seg_teste
FROM tb_turma;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


4º Exemplo

Uma imobiliária faz contratos locação de imóveis por um período de 2 anos e 5 meses. Vamos calcular as datas de encerramento dos contratos. Para calcular as datas de encerramento dos contrato vamos utilizar a tabela "tb_locacao". Veja a imagem da tabela tb_locacao seguir.


Descrição das colunas
  • imovel_id: identificação do imóvel;
  • cliente_id: identificação do cliente;
  • data_inicio_locacao: data de início da locação;
Solução

Podemos acrescentar um intervalo a data.

 data + inverval 'n período'

Onde:
  • inverval: tipo de dado que armazena um intervalo de tempo no PostgreSql;
  • n: valor numérico;
  • período: armazena a unidade de medida de tempo. Neste caso, vamos utilizar duas unidades de tempo, years e months, pois precisamos adicionar anos e meses a coluna data_inicio_locacao;
Para exibir as datas de encerramento dos contratos executamos a consulta abaixo:

SELECT
imovel_id,
cliente_id,
data_inicio_locacao,
data_inicio_locacao + interval '2 years 5 months' AS data_fim_locacao
FROM tb_locacao;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.



Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
imovel_id,
cliente_id,
to_char (data_inicio_locacao, 'dd/mm/yyyy'),
to_char (data_inicio_locacao + interval '2 year 5 months, 'dd/mm/yyyy') AS data_fim_locacao
FROM tb_locacao;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.

Observação

Perceba que foi adicionado um período de 2 anos e 5 meses (2 years 5 months). Também poderíamos adicionar um período de 29 meses (29 months) que retornaria o mesmo resultado. O objetivo deste exemplo é mostrar que é possível adicionar mais de uma unidade de tempo ao período.

5º Exemplo

Uma lanchonete quer que seja exibida em sua nota fiscal a data e o horário de previsão de entrega.
O prazo de entrega são de 40 minutos após a emissão do pedido.
Para exibir a data de previsão vamos utilizar a tabela "tb_pedido". Veja a tabela na imagem abaixo:


Descrição das colunas
  • pedido_codigo: código do pedido;
  • pedido_data: data do pedido;
Solução

Podemos acrescentar um intervalo a data e a hora.

 data_e_hora + inverval 'n período'

Onde:
  • inverval: tipo de dado que armazena um intervalo de tempo no PostgreSql;
  • n: valor numérico;
  • período: armazena a unidade de medida de tempo. Neste caso, vamos utilizar a unidade de tempo minutes, pois precisamos adicionar minutos a coluna pedido_data;
Para exibir a previsão do pedido executamos a consulta abaixo:

SELECT
pedido_codigo,
pedido_data,
pedido_data + interval '40 minutesAS data_entrega
FROM tb_pedido;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Caso haja necessidade, formate as datas através do comando to_char. Veja o comando abaixo:

SELECT
pedido_codigo,
to_char(pedido_data, 'dd/mm/yyyy hh24:mi:ss') AS pedido_data,
to_char(pedido_data + interval '40 minutes' , 'dd/mm/yyyy hh24:mi:ss') AS data_entrega
FROM tb_pedido;

Após a execução da sentença, será exibido o resultado. Veja na imagem a seguir.


Observação

Repare que utilizamos na mascara, hh24:mi:ss, para o horário, logo as horas serão formatadas no intervalo de (00-24) h, devido ao número 24 que acompanha a hora.
Se utilizarmos o formato a mascara hh:mi:ss, as horas serão formatadas no intervalo de (00-12) h.


6º Exemplo

Uma locadora de carros tem que calcular uma data de "devolução de veículos" a partir da data de "início da locação". Neste exemplo, os períodos de locação são variáveis de acordo com a solicitação do cliente.
Neste caso, foi necessário criar uma coluna para armazenar os períodos chamada "periodo".

Vamos utilizar a tabela "tb_loc_auto" para simular esta situação. Veja a imagem a seguir:



Segue o script de criação da tabela:

/*Comando para criar a tabela "tb_loc_auto"*/
CREATE TABLE tb_loc_auto
(
id            serial,
data_inicio timestamp,
periodo       interval,
CONSTRAINT pk_auto_id PRIMARY KEY(id)
);

/*
Comando para inserir múltiplos registros na tabela "tb_loc_auto".
*/
INSERT INTO tb_loc_auto (data_inicio, periodo)
VALUES
('2020-02-13 13:24:12', '2 years'),
('2020-03-14 19:30:15', '2 months'),
('2020-03-15 23:45:42', '2 days'),
('2020-03-16 23:59:30', '2 hours'),
('2020-03-17 23:59:30', '2 minutes'),
('2020-03-18 23:59:30', '2 seconds'),
('2020-03-19 23:59:30', '1 years 6 months 2 days 2 hours 2 minutes 2 seconds');

Para calcular as datas de devolução dos veículos executamos a consulta abaixo:

SELECT
id,
data_inicio,
periodo,
data_inicio + periodo AS data_devolucao
FROM tb_loc_auto;

Após a execução da sentença, será exibido o resultado na coluna "data_devolucao". Veja na imagem a seguir:


Deixe o seu comentário. Suas sugestões ou críticas serão bem-vindas.

5 comentários:

  1. Bastante esclarecedor, rico em exemplos e detalhado. Obrigado!

    ResponderExcluir
  2. Boa tarde, e quando quero somar horas (tempo) como faço?
    Quero somar a quantidade de horas trabalhadas. Qual comando em SQL?

    ResponderExcluir
  3. Quero subtrair não um intervalo fixo como no exemplo:
    data_fim_contrato - interval '3 months'

    Mas sim atrves de outro campo na tabela, exemplo:
    CAMPO1 - interval 'CAMPO2 months'

    Tem uma indicação de como fazer?

    ResponderExcluir
    Respostas
    1. Boa tarde, obrigada por sua pergunta. Desculpa a demora em responder.
      Segue um exemplo de como subtrair um intervalo de uma data utilizando uma coluna com o "tipo de dado interval".

      /*Comando para criar a tabela "tb_cadastro"*/
      CREATE TABLE tb_cadastro
      (
      id serial,
      data_referencia timestamp,
      periodo interval,
      CONSTRAINT pk_cad_id PRIMARY KEY(id)
      );

      /*Comando para inserir múltiplos registros na tabela "tb_cadastro".
      */

      INSERT INTO tb_cadastro(data_referencia, periodo)
      VALUES
      ('2020-03-17 13:24:12', '2 years'),
      ('2020-03-17 19:30:15', '2 months'),
      ('2020-03-17 23:45:42', '2 days'),
      ('2020-03-17 23:59:30', '2 hours'),
      ('2020-03-17 23:59:30', '2 minutes'),
      ('2020-03-17 23:59:30', '2 seconds'),
      ('2020-03-17 23:59:30', '2 years 2 months 2 days 2 hours 2 minutes 2 seconds');

      /*Ao executar a consulta, veja a coluna com o alias "data_alerta", esta coluna é o resultado da subtração de um intervalo (data_referencia - periodo).
      */
      SELECT
      id,
      data_referencia,
      periodo,
      data_referencia - periodo AS data_alerta
      FROM tb_cadastro;

      Excluir