Descobrindo se datas, horas, timestamps se cruzam no SQL (OVERLAPS)

Imagine que você tem uma tabela SQL com calendário de compromissos. Você gostaria de escrever nela um compromisso dia 10/01/2018 das 12:00 às 13:00. Mas espere, antes de inserir esse compromisso na tabela, você quer descobrir se há algum outro compromisso acontecendo das 12:00 às 13:00 do mesmo dia.

Descobri recentemente uma função/operação muito legal padrão do SQL chamada OVERLAPS que ajuda muito nisso.

Ela serve pra comparar se dois eventos de tempo (intervalos de tempo, que tenham um início e um fim) "se encostam", "se sobrepõem", "se interseccionam", "tem intersecção", "conflitam em algum horário".

A função precisa de 4 valores:

  • "Início 1","Fim 1"
  • "Início 2","Fim 2"

Aqui pergunto se as datas 01/01/2018 00:00 até 02/01/2018 00:00 tem intersecção com 01/01/2018 00:00 até 03/01/2018 00:00:

[code language="sql"] SELECT ('2018-01-01 00:00:00'::TIMESTAMP, '2018-01-02 00:00:00'::TIMESTAMP) OVERLAPS ('2018-01-01 00:00:00'::TIMESTAMP, '2018-01-03 00:00:00'::TIMESTAMP);​

--Retorna TRUE, ou seja, os 2 eventos "se encostam" [/code]

Como há intersecção entre os valores, ele retornou VERDADEIRO.

Veja o que acontece neste exemplo:

[code language="sql"] SELECT ('2018-01-01 00:00:00'::TIMESTAMP, '2018-01-02 00:00:00'::TIMESTAMP) OVERLAPS ('2018-01-02 00:00:00'::TIMESTAMP, '2018-01-03 00:00:00'::TIMESTAMP);​ --Retorna FALSE, ou seja, os 2 eventos não "se encostam" [/code]

Retorna FALSO, porque não há intersecção.

Isso acontece porque os valores de Início são intervalo fechado, e os valores de Fim são intervalo aberto.

Outra forma de explicar é:

  • Início é >=
  • Fim é <

Paralelo com os tipos RANGE do PostgreSQL

O OVERLAP é praticamente igual ao operador && do tipo TSRANGE, quando ambos os TSRANGEs forem construídos com '[)' (valor padrão, caso esse atributo não seja informado no construtor).

Referências

https://www.postgresql.org/docs/current/static/functions-datetime.html

https://dba.stackexchange.com/questions/59074/2-b-tree-indices-or-1-gist-index-on-tsrange-which-will-perform-better

You should also read:

Descobrindo tamanho de colunas e tabelas no PostgreSQL

SELECT pg_size_pretty(sum(pg_column_size(coluna_1))) as coluna_1_size, pg_size_pretty(sum(pg_column_size(coluna_2))) as coluna_2_sizeFROM tabela A query retornará algo assim: coluna_1_size, coluna_2_size"163 kB" , "245 kB" Descorbrindo tamanho de tabela,…

Descobrindo tamanho de tabelas e índices no PostgreSQL

select schemaname as table_schema, relname as table_name, pg_size_pretty(pg_total_relation_size(relid)) as total_size, pg_size_pretty(pg_relation_size(relid)) as data_size, pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) as external_sizefrom pg_catalog.pg_statio_user_tablesorder by pg_total_relation_size(relid) desc, pg_relation_size(relid)…

Descobrindo Primary Key de todas as tabelas no PostgreSQL

select kcu.table_schema, kcu.table_name, tco.constraint_name, kcu.ordinal_position as position, kcu.column_name as key_columnfrom information_schema.table_constraints tcojoin information_schema.key_column_usage kcu on kcu.constraint_name = tco.constraint_name and kcu.constraint_schema = tco.constraint_schemawhere tco.constraint_type…