Como criar tabelas temporais no SQL Server: passo a passo
As tabelas temporais (system-versioned) do SQL Server guardam automaticamente o histórico de cada linha e deixam-no consultar os dados tal como estavam em qualquer momento do passado. São perfeitas para auditoria, análise de alterações e para recuperar valores alterados por engano, sem escrever triggers nem manter tabelas de histórico à mão. É uma das formas mais simples de acrescentar rastreabilidade e governança a um modelo de dados existente.
Pré-requisitos
- SQL Server 2016 ou superior, ou uma base de dados no Azure SQL Database.
- SQL Server Management Studio (SSMS) ou Azure Data Studio para executar as consultas.
- Permissões para criar tabelas numa base de dados de teste (evite produção).
- Conhecimentos básicos de T-SQL:
CREATE TABLE,INSERT,UPDATEeSELECT.
Passo 1: Criar a tabela temporal
Uma tabela temporal precisa de três coisas: uma chave primária, duas colunas datetime2 que marcam o início e o fim de validade de cada versão da linha, e a cláusula PERIOD FOR SYSTEM_TIME. As colunas de período são preenchidas pelo motor (repare no GENERATED ALWAYS AS ROW START/END), pelo que nunca lhes escreve valores. Ao contrário de uma solução com triggers, o versionamento é gerido pelo próprio SQL Server. Ativamo-lo com SYSTEM_VERSIONING = ON e damos um nome à tabela de histórico.
CREATE TABLE dbo.Funcionario
(
FuncionarioID INT NOT NULL PRIMARY KEY CLUSTERED,
Nome NVARCHAR(100) NOT NULL,
Departamento NVARCHAR(50) NOT NULL,
Salario DECIMAL(10,2) NOT NULL,
ValidoDe DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
ValidoAte DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidoDe, ValidoAte)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.FuncionarioHistorico));
O SQL Server cria automaticamente a tabela dbo.FuncionarioHistorico com a mesma estrutura. É aí que ficam guardadas, de forma transparente, as versões antigas de cada linha. Os valores de período são gravados em UTC.
A tabela de histórico só cresce. Em cenários reais, defina uma política de retenção (HISTORY_RETENTION_PERIOD) para apagar versões antigas de forma automática e controlar o espaço ocupado.
Passo 2: Inserir e alterar dados
Repare que não indicamos valores para as colunas de período — o motor trata disso. Vamos inserir um funcionário e, mais tarde, dar-lhe um aumento.
INSERT INTO dbo.Funcionario (FuncionarioID, Nome, Departamento, Salario)
VALUES (1, N'Ana Silva', N'Dados', 3000.00);
-- Some time later, Ana gets a raise:
UPDATE dbo.Funcionario
SET Salario = 3500.00
WHERE FuncionarioID = 1;
No momento do UPDATE, a versão anterior (salário 3000) é copiada para a tabela de histórico com o intervalo de validade em que esteve ativa, e a linha atual fica com o valor novo.
Passo 3: Consultar o histórico com FOR SYSTEM_TIME
Uma consulta normal devolve apenas o estado atual. Para ver como estavam os dados num instante específico, use FOR SYSTEM_TIME AS OF:
-- Replace with a real date/time between the insert and the raise
SELECT FuncionarioID, Nome, Salario, ValidoDe, ValidoAte
FROM dbo.Funcionario
FOR SYSTEM_TIME AS OF '2026-07-07 15:00:00'
WHERE FuncionarioID = 1;
O SQL Server devolve a versão que estava válida nesse momento — mesmo que já tenha sido substituída. Para ver todas as versões de uma linha, atuais e históricas, de uma só vez, use ALL:
SELECT FuncionarioID, Nome, Salario, ValidoDe, ValidoAte
FROM dbo.Funcionario
FOR SYSTEM_TIME ALL
WHERE FuncionarioID = 1
ORDER BY ValidoDe;
Passo 4: Desativar o versionamento em segurança
Não se pode apagar nem alterar a estrutura de uma tabela temporal diretamente. Primeiro desliga-se o versionamento; a ligação à tabela de histórico é removida, mas os dados mantêm-se intactos.
ALTER TABLE dbo.Funcionario SET (SYSTEM_VERSIONING = OFF);
-- You can now alter columns or drop tables if needed.
-- To re-enable, point again to the same history table.
Verificar o resultado
Uma consulta simples (SELECT * FROM dbo.Funcionario) deve mostrar apenas a versão atual, com o salário 3500. Se a consulta com FOR SYSTEM_TIME ALL devolver duas linhas para o FuncionarioID 1 — uma com 3000 e outra com 3500 — o versionamento está a funcionar. No SSMS, a tabela aparece com um ícone de relógio e, ao expandi-la, mostra a tabela de histórico associada por baixo.
Conclusão
Com poucas linhas de T-SQL passou a ter um histórico automático e à prova de esquecimentos, pronto para auditorias e para responder à pergunta "como é que isto estava antes?". O passo seguinte é explorar as variantes FROM ... TO, BETWEEN ... AND e CONTAINED IN para consultar intervalos de tempo, e definir uma política de retenção adequada. Que tabela do seu modelo beneficiaria já de guardar o seu próprio histórico?