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

Cómo crear tablas Ledger en Azure SQL: paso a paso

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

Las tablas Ledger de Azure SQL guardan un historial protegido criptográficamente de todos los cambios en los datos. Crear tablas Ledger en Azure SQL permite demostrar a un auditor que ningún registro fue manipulado, sin escribir una sola línea de código en la aplicación: el propio motor registra cada INSERT, UPDATE y DELETE.

Requisitos previos

  • Una base de datos en Azure SQL Database (la funcionalidad también existe en SQL Server 2022 y posteriores).
  • Permisos para crear tablas (por ejemplo, ser miembro de db_owner).
  • SQL Server Management Studio (SSMS) o Azure Data Studio conectado a la base de datos.
  • Conocimientos básicos de T-SQL.

Paso 1: Elegir el tipo de tabla Ledger

Existen dos tipos y la elección depende de lo que la tabla necesite hacer:

  • Updatable ledger table — acepta INSERT, UPDATE y DELETE. Cada cambio queda registrado en una tabla de historial y visible en una vista Ledger.
  • Append-only ledger table — solo acepta INSERT. Cualquier intento de UPDATE o DELETE es bloqueado por el motor. Ideal para logs de eventos o registros de accesos.

Para datos de negocio que cambian (pagos, contratos, saldos) use la versión actualizable. Para datos que nunca deberían cambiar, use append-only.

Paso 2: Crear una tabla Ledger actualizable

La creación es un CREATE TABLE normal con la cláusula LEDGER = ON. Conviene dar nombres explícitos a la tabla de historial y a la vista Ledger, para encontrarlas fácilmente después:

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)
);

El motor crea automáticamente columnas de sistema que identifican la transacción que insertó o eliminó cada versión de la fila.

Paso 3: Insertar y modificar datos

A partir de aquí trabaja con la tabla como con cualquier otra. No hace falta sintaxis 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';

Paso 4: Consultar el historial en la vista Ledger

La vista Ledger muestra lo que ocurrió con cada fila a lo largo del tiempo. Un UPDATE aparece como un par de operaciones: la versión antigua se marca como DELETE y la nueva 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;

Es ese par INSERT/DELETE lo que permite reconstruir el valor de cualquier fila en cualquier momento del pasado.

Paso 5: Descubrir quién ejecutó cada transacción

La vista de sistema sys.database_ledger_transactions guarda el autor y el momento de cada transacción registrada:

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

Al cruzar transaction_id con ledger_transaction_id de la vista Ledger, sabrá quién cambió qué y cuándo.

Paso 6: Crear una tabla append-only

Para registros que nunca deben modificarse, como un log de accesos:

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 el resultado

Primero, confirme que las tablas se crearon con el tipo Ledger correcto:

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

Después, haga la prueba que realmente importa: intente modificar una fila de la tabla append-only.

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

El motor devuelve un error y la operación no se realiza — ni siquiera el administrador de la base de datos puede forzarla. En la tabla actualizable el UPDATE funciona, pero la versión anterior sigue visible en la vista dbo.Pagamentos_Ledger. Si ocurren ambas cosas, todo está correcto.

Conclusión

En pocos minutos ha conseguido, dentro de la base de datos, una garantía de integridad que antes exigía triggers, tablas de auditoría manuales y mucha confianza. El siguiente paso es automatizar la generación de digests hacia almacenamiento inmutable y luego usar los procedimientos de verificación del Ledger para demostrar, matemáticamente, que el historial no fue tocado. Un consejo final: una tabla Ledger no desaparece con un DROP TABLE — queda marcada como dropped y el historial se mantiene. ¿Cuál de sus tablas actuales ganaría más si pasara a append-only?