(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como criar tabelas Ledger no Azure SQL: passo a passo

João Barros 11 de July de 2026 4 min de leitura

As tabelas Ledger do Azure SQL guardam um histórico protegido por criptografia de todas as alterações aos dados. Criar tabelas Ledger no Azure SQL permite provar a um auditor que nenhum registo foi adulterado, sem escrever uma linha de código na aplicação: o próprio motor regista cada INSERT, UPDATE e DELETE.

Pré-requisitos

  • Uma base de dados no Azure SQL Database (a funcionalidade também existe no SQL Server 2022 e superior).
  • Permissões para criar tabelas (por exemplo, ser membro de db_owner).
  • SQL Server Management Studio (SSMS) ou Azure Data Studio ligado à base de dados.
  • Noções básicas de T-SQL.

Passo 1: Escolher o tipo de tabela Ledger

Existem dois tipos e a escolha depende do que a tabela precisa de fazer:

  • Updatable ledger table — aceita INSERT, UPDATE e DELETE. Cada alteração fica registada numa tabela de histórico e fica visível numa vista Ledger.
  • Append-only ledger table — só aceita INSERT. Qualquer tentativa de UPDATE ou DELETE é bloqueada pelo motor. Ideal para logs de eventos ou registos de acessos.

Para dados de negócio que mudam (pagamentos, contratos, saldos) use a versão atualizável. Para dados que nunca deveriam mudar, use append-only.

Passo 2: Criar uma tabela Ledger atualizável

A criação é um CREATE TABLE normal com a cláusula LEDGER = ON. Vale a pena dar nomes explícitos à tabela de histórico e à vista Ledger, para depois as encontrar facilmente:

CREATE TABLE dbo.Pagamentos
(
    PagamentoID INT IDENTITY(1,1) PRIMARY KEY,
    Cliente     NVARCHAR(100) NOT NULL,
    Valor       DECIMAL(10,2) NOT NULL,
    Estado      NVARCHAR(20)  NOT NULL
)
WITH (
    SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Pagamentos_History),
    LEDGER = ON (LEDGER_VIEW = dbo.Pagamentos_Ledger)
);

O motor cria automaticamente colunas de sistema que identificam a transação que inseriu ou apagou cada versão da linha.

Passo 3: Inserir e alterar dados

A partir daqui trabalha com a tabela como com qualquer outra. Não é preciso sintaxe especial:

INSERT INTO dbo.Pagamentos (Cliente, Valor, Estado)
VALUES (N'Ana Silva', 250.00, N'Pendente');

UPDATE dbo.Pagamentos
SET Estado = N'Pago'
WHERE Cliente = N'Ana Silva';

Passo 4: Consultar o histórico na vista Ledger

A vista Ledger mostra o que aconteceu a cada linha ao longo do tempo. Um UPDATE aparece como um par de operações: a versão antiga é marcada como DELETE e a nova como INSERT.

SELECT Cliente,
       Valor,
       Estado,
       ledger_transaction_id,
       ledger_sequence_number,
       ledger_operation_type_desc
FROM dbo.Pagamentos_Ledger
ORDER BY ledger_transaction_id, ledger_sequence_number;

É este par INSERT/DELETE que permite reconstruir o valor de qualquer linha em qualquer momento do passado.

Passo 5: Descobrir quem fez cada transação

A vista de sistema sys.database_ledger_transactions guarda o autor e o momento de cada transação registada:

SELECT t.transaction_id,
       t.principal_name,
       t.commit_time
FROM sys.database_ledger_transactions AS t
ORDER BY t.commit_time DESC;

Cruzando o transaction_id com o ledger_transaction_id da vista Ledger fica a saber quem mudou o quê e quando.

Passo 6: Criar uma tabela append-only

Para registos que nunca devem ser alterados, como um log de acessos:

CREATE TABLE dbo.Acessos
(
    AcessoID  INT IDENTITY(1,1) PRIMARY KEY,
    Utilizador NVARCHAR(100) NOT NULL,
    DataHora   DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME()
)
WITH (LEDGER = ON (APPEND_ONLY = ON));

Verificar o resultado

Primeiro, confirme que as tabelas foram criadas com o tipo Ledger correto:

SELECT name, ledger_type_desc
FROM sys.tables
WHERE ledger_type_desc IS NOT NULL;

Depois, faça o teste que realmente interessa: tente alterar uma linha da tabela append-only.

UPDATE dbo.Acessos SET Utilizador = N'outro' WHERE AcessoID = 1;

O motor devolve um erro e a operação não acontece — nem o administrador da base de dados a consegue forçar. Na tabela atualizável, o UPDATE funciona, mas a versão anterior continua visível na vista dbo.Pagamentos_Ledger. Se as duas coisas acontecerem, está tudo correto.

Conclusão

Em poucos minutos passou a ter, na base de dados, uma prova de integridade que antes exigia triggers, tabelas de auditoria manuais e muita confiança. O passo seguinte é automatizar a geração de digests para armazenamento imutável e depois usar os procedimentos de verificação do Ledger para provar, matematicamente, que o histórico não foi tocado. Uma dica final: uma tabela Ledger não desaparece com um DROP TABLE — fica marcada como dropped e o histórico mantém-se. Qual das suas tabelas atuais ganharia mais em passar a append-only?