No último post, comentei que para trabalhar corretamente no PostgreSQL, você tem de começar inserindo e exibindo corretamente os seus dados. Agora vamos brincar um pouco de aritmética, dando ênfase ao tipo de dados INTERVAL. Numa comparação entre diversos SGDBs vemos que alguns representantes de peso como MySQL, MS SQL Server não possuem o tipo de dados INTERVAL. O SQLite, que é muito bacana não tem nenhum tipo nativo para trabalhar com datas e o Oracle possui 2 tipos separados para trabalhar com intervalos. Uma bagunça. Só para lembrar, o tipo de dados ‘INTERVAL’ foi padronizado há muito tempo, no SQL 92!
- Não é possível somar dois campos do tipo DATE e/ou TIMESTAMP:
# SELECT DATE'2012-12-18' + DATE'2012-08-05'; ERROR: operator does not exist: date + date at character 25 HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. # SELECT TIMESTAMP'2012-12-18' + TIMESTAMP'2012-08-05'; ERROR: operator does not exist: timestamp without time zone + timestamp without time zone at character 30 HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
- A subtração de duas datas é sempre um intervalo:
# SELECT current_date - DATE'2012-11-18' AS intervalo; intervalo ----------- 30 (1 row)
- A soma de um intervalo com uma data é sempre uma data:
# SELECT current_date + INTERVAL'2 days' AS data; data --------------------- 2012-12-20 00:00:00 (1 row) # SELECT current_date + 3* INTERVAL'1 day' AS data; data --------------------- 2012-12-21 00:00:00
- A soma de dois intervalos é sempre um intervalo:
# SELECT INTERVAL'3 hour' + INTERVAL'1.5 days' AS intervalo; intervalo ---------------- 1 day 15:00:00 (1 row)
- Um intervalo pode ser multiplicado por um número inteiro ou de ponto flutuante:
# SELECT INTERVAL'1 hour' / 2 AS intervalo; intervalo ----------- 00:30:00 (1 row) # SELECT INTERVAL'1 hour' / FLOAT'1.5' AS intervalo; intervalo ----------- 00:40:00 (1 row)
- Você pode transformar um intervalo num número extraindo a quantidade de segundos de um intervalo com a função EXTRACT com o parâmetro EPOCH:
# SELECT EXTRACT(EPOCH FROM INTERVAL '1 day') AS segundos; segundos ---------- 86400 (1 row) # SELECT EXTRACT(EPOCH FROM INTERVAL '2 days 3 hours')/(60*60) AS horas; horas ------- 51 (1 row) # SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 12 hours')/(60*60*24) AS dias; ?column? ---------- 5.5 (1 row)
Eu sou particularmente fã de intervalos. Muita gente acredita que usando campos numéricos para armazenar intervalos você simplifica as coisas, mas como você pode ver, tudo aqui é bastante direto e reto. Nada de conversões de segundo para hora, de dia para ano. Tudo simples. Se um dia você precisar indexar intervalos ou utilizar intervalos em cálculos mais complexos envolvendo data e hora, você verá que utilizar intervalos é uma estratégia inteligente.