0Pricing
SQL Academy · Aula

Linhas Temporais e Versionadas

Consultas por tempo de validade e no estado de uma data específica.

Linhas Temporais e Versionadas é uma aula grátis de SQL Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de SQL Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de SQL Academy inclui 4 aulas no total.

O que são tabelas temporais?

As tabelas temporais permitem acompanhar como os dados mudam ao longo do tempo. Em vez de sobrescrever uma linha quando algo muda, uma tabela temporal mantém todas as versões dessa linha, cada uma identificada pelo período em que foi válida.

Há dois conceitos principais: tempo de validade (quando o fato era verdadeiro no mundo real) e tempo da transação (quando o banco de dados registrou o fato). A combinação dos dois resulta em uma tabela totalmente bitemporal.

Tempo de validade versus tempo da transação

Tempo de validade representa quando um fato é verdadeiro no mundo real — por exemplo, o salário de um funcionário de 2020-01-01 a 2022-06-30. Tempo da transação é quando a linha do banco de dados foi inserida ou expirada. Juntos, eles respondem a duas perguntas: O que era verdadeiro? e Quando ficamos sabendo disso?

A maioria dos casos de uso práticos começa pelo acompanhamento do tempo de validade, que você pode implementar manualmente usando as colunas valid_from e valid_to.

Criando uma tabela com tempo de validade

A maneira mais simples de armazenar linhas versionadas é adicionar colunas de carimbo de data e hora valid_from e valid_to. Um valor NULL em valid_to (ou um marcador de data futura distante, como 9999-12-31) significa que a linha está ativa no momento.

CREATE TABLE employee_salary (
  id          SERIAL PRIMARY KEY,
  employee_id INT NOT NULL,
  salary      NUMERIC(12, 2) NOT NULL,
  valid_from  DATE NOT NULL,
  valid_to    DATE
);

INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES
  (1, 50000, '2020-01-01', '2022-06-30'),
  (1, 60000, '2022-07-01', NULL);

Consultando a versão atual

Para encontrar a linha atualmente ativa de cada funcionário, filtre as linhas em que valid_to IS NULL (sem fim definido) ou em que a data de hoje esteja dentro do intervalo de validade. Usar um marcador como '9999-12-31' simplifica as comparações de intervalos.

SELECT employee_id, salary
FROM employee_salary
WHERE valid_to IS NULL
ORDER BY employee_id;

Consultas referentes a um momento específico

Uma consulta referente a um momento específico pergunta: Quais eram os dados em um determinado momento? Você filtra as linhas em que o carimbo de data e hora informado esteja dentro do período de validade. Essa é uma das funcionalidades mais poderosas das tabelas temporais.

-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_from, valid_to
FROM employee_salary
WHERE employee_id = 1
  AND valid_from <= '2021-03-15'
  AND (valid_to IS NULL OR valid_to > '2021-03-15');

Atualizando uma linha versionada

Quando um fato muda, você não executa UPDATE na linha existente. Em vez disso, você fecha a linha atual definindo seu valor de valid_to e insere uma nova linha com o novo valor. Isso preserva o histórico completo.

-- Employee 1 gets a raise effective 2023-01-01
BEGIN;

-- Close the current open row
UPDATE employee_salary
SET valid_to = '2022-12-31'
WHERE employee_id = 1
  AND valid_to IS NULL;

-- Insert the new version
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES (1, 72000, '2023-01-01', NULL);

COMMIT;

Usando daterange para períodos de validade

O tipo daterange do PostgreSQL representa com elegância um período de validade em uma única coluna. Você pode usar o operador @> (contém) para verificar se uma data está dentro do intervalo e adicionar uma restrição de exclusão para impedir períodos sobrepostos da mesma entidade.

CREATE TABLE employee_salary_v2 (
  id          SERIAL PRIMARY KEY,
  employee_id INT NOT NULL,
  salary      NUMERIC(12, 2) NOT NULL,
  valid_period DATERANGE NOT NULL,
  EXCLUDE USING GIST (employee_id WITH =, valid_period WITH &&)
);

INSERT INTO employee_salary_v2 (employee_id, salary, valid_period)
VALUES
  (1, 50000, '[2020-01-01, 2022-07-01)'),
  (1, 60000, '[2022-07-01, infinity)');

Consulta referente a um momento específico com daterange

Com a abordagem daterange, a consulta referente a um momento específico fica muito legível. O operador @> verifica se a data informada está contida no intervalo, tratando automaticamente os limites inferior e superior.

-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_period
FROM employee_salary_v2
WHERE employee_id = 1
  AND valid_period @> '2021-03-15'::date;

Tabelas com versionamento do sistema (padrão SQL)

O padrão SQL:2011 introduziu as tabelas temporais com versionamento do sistema. O banco de dados gerencia automaticamente as colunas de tempo da transação row_start e row_end. No PostgreSQL, você simula esse comportamento; no SQL Server e no MariaDB, ele é integrado com SYSTEM VERSIONING.

O exemplo abaixo mostra a sintaxe do SQL Server / MariaDB como referência para o conceito.

-- SQL Server / MariaDB syntax (reference)
CREATE TABLE dbo.Product (
  ProductID   INT PRIMARY KEY,
  Name        VARCHAR(100),
  Price       DECIMAL(10,2),
  SysStart    DATETIME2 GENERATED ALWAYS AS ROW START,
  SysEnd      DATETIME2 GENERATED ALWAYS AS ROW END,
  PERIOD FOR SYSTEM_TIME (SysStart, SysEnd)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Product_History));

Junções temporais: alinhando duas tabelas no tempo

Um desafio comum é fazer a junção de duas tabelas temporais com base em períodos correspondentes. Por exemplo, juntar salários de funcionários a atribuições de departamentos quando ambos têm períodos de validade. A junção usa a chave da entidade AND a condição de sobreposição, por meio de && nos intervalos ou de comparações explícitas de datas.

CREATE TABLE dept_assignment (
  employee_id INT,
  department  VARCHAR(50),
  valid_period DATERANGE
);

INSERT INTO dept_assignment VALUES
  (1, 'Engineering', '[2020-01-01, infinity)'),
  (1, 'Marketing',   '[2019-01-01, 2020-01-01)');

-- Periods where employee 1 was in Engineering AND had salary > 55000
SELECT s.salary, d.department,
       s.valid_period * d.valid_period AS overlap_period
FROM employee_salary_v2 s
JOIN dept_assignment d
  ON s.employee_id = d.employee_id
  AND s.valid_period && d.valid_period
WHERE s.employee_id = 1
  AND s.salary > 55000;

Impedindo lacunas e sobreposições

Dois problemas comuns de qualidade de dados em tabelas temporais são as lacunas (períodos sem registro) e as sobreposições (duas linhas válidas ao mesmo tempo). A restrição de exclusão com && impede sobreposições no nível do banco de dados. Detectar lacunas exige verificar a existência de cobertura ausente com uma consulta.

-- Find gaps in salary history for employee 1
-- (periods where upper(prev) < lower(next))
SELECT
  upper(a.valid_period) AS gap_start,
  lower(b.valid_period) AS gap_end
FROM employee_salary_v2 a
JOIN employee_salary_v2 b
  ON a.employee_id = b.employee_id
  AND upper(a.valid_period) < lower(b.valid_period)
WHERE a.employee_id = 1
  AND NOT EXISTS (
    SELECT 1 FROM employee_salary_v2 c
    WHERE c.employee_id = 1
      AND lower(c.valid_period) > upper(a.valid_period)
      AND lower(c.valid_period) < lower(b.valid_period)
  )
ORDER BY gap_start;

Verificação de conhecimentos

Teste sua compreensão sobre tabelas temporais e consultas referentes a um momento específico.

Recapitulação: linhas temporais e versionadas

Nesta lição, você aprendeu a modelar dados que variam ao longo do tempo usando colunas de tempo de validade e o tipo daterange do PostgreSQL. Principais aprendizados:

  • Nunca sobrescreva linhas históricas — feche a antiga e insira uma nova versão.
  • Use consultas referentes a um momento específico (valid_from <= target AND valid_to > target) para recuperar dados de qualquer momento passado.
  • O tipo daterange com o operador @> torna as consultas temporais concisas e legíveis.
  • Restrições de exclusão em && (sobreposição de intervalos) garantem a integridade dos dados no nível do banco de dados.
  • Junções temporais alinham dois históricos cruzando seus períodos de validade.

Esses padrões formam a base da origem de eventos, do registro de auditoria e de qualquer sistema em que a precisão histórica seja importante.

Perguntas Frequentes

A aula “Linhas Temporais e Versionadas” é grátis?

Sim — o texto completo de “Linhas Temporais e Versionadas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de SQL Academy, atualize para CoddyKit PRO. O curso de SQL Academy inclui 4 aulas no total.

O que vou aprender em “Linhas Temporais e Versionadas”?

Consultas por tempo de validade e no estado de uma data específica. Você pratica SQL Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar SQL Academy?

Nenhuma experiência prévia é necessária. SQL Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Linhas Temporais e Versionadas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de SQL Academy?

Sim. Cada aula de SQL Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por Que Manter o Histórico
  2. Tabelas de Eventos Somente para Acréscimo
  3. Linhas Temporais e Versionadas
  4. Reconstruindo o Estado a Partir de Eventos
← Voltar para SQL Academy