SQLDiff Guía de bolsilloPocket Guide
GitHub

Cambia la forma, conserva las filas Change the shape, keep the rows

Todos los comandos de sqldiff en una página. Compara dos bases de SQL Server y escribe el script de migración que lleva una a la forma de la otra — sin borrar tus tablas.

Every sqldiff command on one page. Compare two SQL Server databases and write the migration script that brings one to the shape of the other — without dropping your tables.

check-conndiffleer el .sqlread the .sql apply|deploy|drift → exit 2
El script generado es el producto. diff nunca toca el destino: escribe un archivo. Léelo, mételo en un pull request, dáselo a un DBA. The generated script is the product. diff never touches the target — it writes a file. Read it, put it in a pull request, hand it to a DBA.
01

InstalaciónInstall

Binario autocontenido, herramienta global de .NET, o compilar. Corre en Windows, Linux y macOS, contra SQL Server 2016 o superior — cualquier edición, Azure SQL incluida.

Self-contained binary, .NET global tool, or a build. Runs on Windows, Linux and macOS, against SQL Server 2016 or newer — any edition, Azure SQL included.

Binario o herramientaBinary or tool

# herramienta global: instala el comando `sqldiff`global tool: installs the `sqldiff` command
dotnet tool install --global PeopleWorks.SqlSchemaDiff.Cli

sqldiff --version
sqldiff --help

O baja el binario autocontenido para Windows o Linux desde Releases ↗: no hay runtime que instalar al lado, viene incluido.

Or download the self-contained binary for Windows or Linux from Releases ↗: nothing to install alongside it, the runtime is bundled.

Compilar desde el códigoBuild from source

git clone https://github.com/peopleworks/SqlSchemaDiff.git
cd SqlSchemaDiff
dotnet build SqlSchemaDiff.csproj -c Release
dotnet bin/Release/net9.0/sqldiff.dll --help
.NET 9
SDK para compilar; el binario del release no lo necesitaSDK to build; the release binary needs none
SQL Server
2016+ — Developer, Express, Azure SQL
SO / OS
Windows · Linux · macOS
02

ConexionesConnections

Antes de comparar nada, conviene saber cómo entregar la cadena de conexión sin dejarla escrita en el historial del shell.

Before comparing anything, it is worth knowing how to hand over the connection string without leaving it in your shell history.

Una contraseña escrita como argumento no es privada. Cualquier otro proceso de la máquina puede leer la línea de comandos completa, el shell la escribe en su historial y la mayoría de los runners de CI la hacen eco. A password typed as a command-line argument is not private. Any other process on the machine can read the full command line, your shell writes it to history, and most CI runners echo it.

Tres formas más segurasThree safer forms

# un archivo cuyos permisos controlasa file whose permissions you control
sqldiff extract --conn-file ./prod.conn

# indirección por variable nombradaindirection through a named variable
sqldiff extract --conn env:MY_CONN

# la variable por defectothe default variable
SQLDIFF_CONN="Server=…" sqldiff extract

Los dos lados tienen las mismas tres formas.

Both sides have the same three forms.

LadoSide OpcionesOptions
ÚnicoSingle--conn · --conn-file · SQLDIFF_CONN
OrigenSource--source-conn · --source-conn-file · SQLDIFF_SOURCE_CONN
DestinoTarget--target-conn · --target-conn-file · SQLDIFF_TARGET_CONN

Verificar antes de compararVerify before comparing

Imprime servidor, base, login, versión y edición de cada lado. Es el primer comando que conviene correr en una máquina nueva.

Prints server, database, login, version and edition for each side. It is the first command worth running on a new machine.

sqldiff check-conn --source-conn "$DEV" --target-conn "$PROD"

En Windows, sin contraseñaOn Windows, no password at all

Server=SQL1;Database=App;Integrated Security=True;
Encrypt=True;TrustServerCertificate=True
TrustServerCertificate=True es para servidores internos y de desarrollo. En producción, use un certificado en el que el cliente confíe. TrustServerCertificate=True is for internal and development servers. In production, use a certificate the client trusts.
03

Inicio rápidoQuick start

La secuencia habitual. El paso 3 es el que importa.

The usual sequence. Step 3 is the one that matters.

SQLDiff lleva una tabla de tres filas a la forma del origen: agrega una columna Tier y ensancha Email con sentencias ALTER, y las mismas tres filas siguen ahí después.
El destino conserva sus filas. Solo cambia la forma — y el script está antes de que algo corra.
The target keeps its rows. Only the shape changes — and you get the script before anything runs.
# 1 · verificar que alcanzas los dos ladosmake sure you can reach both sides
sqldiff check-conn --source-conn "$DEV" --target-conn "$PROD"

# 2 · escribir el script; no se aplica nadawrite the script; nothing is applied
sqldiff diff --source-conn "$DEV" --target-conn "$PROD" --out changes.sql

# 3 · LEER changes.sql. Este es el paso que importa.READ changes.sql. This is the step that matters.

# 4 · aplicarloapply it
sqldiff apply --conn "$PROD" --script changes.sql --log apply.log

Si prefiere un solo paso, deploy es diff + apply junto, y la aplicación corre en una transacción que revierte entera.

If you would rather do it in one step, deploy is diff + apply together, and the apply runs in one transaction that rolls back whole.

sqldiff deploy --source-conn "$DEV" --target-conn "$PROD" --out changes.sql
Un script generado es un delta para un par concreto de bases, así que no está pensado para reejecutarse: aplicarlo dos veces falla en los objetos que ya creó. Para volver a poner un destino al día, corra diff/deploy otra vez — contra un destino que ya coincide, produce un script vacío y no hace nada. A generated script is a delta for one specific pair of databases, so it is not meant to be re-run: applying it twice fails on the objects it already created. To bring a target up to date again, run diff/deploy again — against a target that already matches, it produces an empty script and does nothing.
04

ComandosCommands

Seis comandos. Tres de ellos escriben en una base; los otros tres solo leen y producen archivos.

Six commands. Three of them write to a database; the other three only read and produce files.

ComandoCommand ¿Escribe?Writes? Qué haceWhat it does
check-connnoVerifica la conexión e imprime servidor, base, login, versión y ediciónVerifies a connection and prints server, database, login, version and edition
extractnoGuiona una base entera a .sql, y opcionalmente un snapshot .jsonScripts a whole database to .sql, and optionally a .json snapshot
diffnoCompara origen contra destino y escribe el script. Nunca toca el destino.Compares source against target and writes the migration script. Never touches the target.
driftnoComo diff, pero sale con código 2 cuando algo difiere. Hecho para CI.Like diff, but exits 2 when anything differs. Built for CI.
applyyesCorre un script existente contra una base, en una sola transacciónRuns an existing script against a database, in one transaction
deployyesdiff + apply en un paso. sync es lo mismo con --apply explícito.diff + apply in one step. sync is the same with an explicit --apply.

extract

sqldiff extract --conn "$DEV" `
  --out schema.sql `
  --json schema.snapshot.json

--out por defecto es schema.sql. --json es opcional y es lo que habilita comparar sin las dos bases en línea.

--out defaults to schema.sql. --json is optional, and it is what makes comparing without both databases online possible.

apply

sqldiff apply --conn "$PROD" `
  --script changes.sql `
  --log apply.log `
  --timeout-seconds 600

El timeout por defecto es de 120 segundos por lote. Súbalo si la migración crea índices grandes.

The default timeout is 120 seconds per batch. Raise it when the migration builds large indexes.

05

FiltrosFilters

Un patrón es [tipo:]glob, donde el tipo es table, view, proc o func, y el glob acepta * y ? contra esquema.nombre o el nombre pelado. Varios se separan con comas.

A pattern is [type:]glob, where the type is table, view, proc or func, and the glob takes * and ? against schema.name or the bare name. Separate several with commas.

sqldiff diff--include "Sales.*"                    # un esquemaone schema
sqldiff diff--include "table:"                     # solo tablastables only
sqldiff diff--exclude "proc:usp_Temp*,dbo.Audit*"  # saltar temporales y auditoríaskip scratch procs and audit tables
sqldiff diff--include "dbo.Customer,dbo.Order*"    # un puñado con nombrea named handful
Los filtros aplican a los dos lados. Eso importa: filtrar solo el origen dejaría un objeto saltado con aspecto de existir solo en el destino, y una corrida posterior con --include-drops borraría justo lo que pidió dejar en paz. Filters apply to both sides. That matters: filtering only the source would leave a skipped object looking target-only, and a later --include-drops run would delete the very thing you asked it to leave alone.

Una corrida filtrada lo dice en la primera línea de su salida, así que una comparación estrechada nunca se confunde con una limpia:

A filtered run says so on the first line of its output, so a narrowed comparison is never mistaken for a clean one:

Filtered comparison (include=table:, exclude=dbo.T7); objects
outside the filter were not compared.
06

Snapshots

Comparar sin tener las dos bases en línea al mismo tiempo.

Comparing without both databases online at the same time.

extract --json escribe la estructura del origen en un archivo. Cométalo, envíelo, compare contra él más tarde — útil cuando el origen es una máquina de desarrollo y el destino es el servidor de un cliente que alcanza una vez al mes.

extract --json writes the source structure to a file. Commit it, ship it, diff against it later — useful when the source is a developer machine and the target is a customer server you reach once a month.

sqldiff extract --conn "$DEV" --out schema.sql --json schema.snapshot.json

sqldiff deploy --source-snapshot schema.snapshot.json `
  --target-conn "$CUSTOMER" --add-only
--source-snapshot
usa un .json como origen en vez de una conexiónuse a .json as the source instead of a connection
--target-snapshot
lo mismo del lado del destinothe same on the target side
--add-only
solo agrega lo que falta; no modifica lo existenteonly adds what is missing; leaves existing objects alone
07

SeguridadSafety

Esta herramienta escribe DDL contra bases que tienen datos adentro, así que los valores por defecto son conservadores.

This is a tool that writes DDL against databases with data in them, so the defaults lean conservative.

Una transacciónOne transaction

apply, sync y deploy corren cada lote en una sola transacción. Si un lote falla, el cambio entero se revierte y el destino queda exactamente como estaba. --no-transaction se sale de eso.

apply, sync and deploy run every batch in a single transaction. If any batch fails, the whole change rolls back and the target is left exactly as it was. --no-transaction opts out.

Nada se borra si no lo pideNothing is dropped unless you ask

Una columna, constraint o índice que solo existe en el destino se reporta como comentario -- WARNING: y se deja en su lugar.

A column, constraint or index that exists only on the target is reported as a -- WARNING: comment and left in place.

--include-drops
habilita borrar esos objetosenables dropping those objects
--include-table-drops
borrar tablas enteras necesita esto encimadropping whole tables needs this on top
--allow-table-rebuild
permite reconstruir una tabla cuando un ALTER no alcanzaallows rebuilding a table when an ALTER cannot do it

EnsayarRehearse

# no escribe: muestra lo que haríawrites nothing: shows what it would do
sqldiff deploy --source-conn "$DEV" --target-conn "$PROD" --dry-run

# deja constancia de lo aplicadoleave a record of what was applied
sqldiff apply --conn "$PROD" --script changes.sql --log apply.log
Los ALTER que emite preservan las filas que ya están ahí. Ese es el punto entero de la herramienta: cambiar la forma sin reconstruir la tabla. The ALTER statements it emits preserve the rows already there. That is the whole point of the tool: change the shape without rebuilding the table.
08

Drift en CIDrift in CI

drift sale con 2 cuando las bases difieren y con 0 cuando coinciden — así un pipeline puede fallar la build cuando producción divergió en silencio del esquema del repositorio.

drift exits 2 when the databases differ and 0 when they match — so a pipeline can fail the build when production has quietly diverged from the schema in your repository.

GitHub Actions

- name: Fail if production drifted
  run: |
    sqldiff drift \
      --source-snapshot schema.snapshot.json \
      --target-conn "$PROD_CONN" \
      --out drift.sql
  env:
    PROD_CONN: ${{ secrets.PROD_CONN }}

Códigos de salidaExit codes

0ÉxitoSuccess
1Error — el mensaje va a stderrError — the message is on stderr
2Drift detectado (solo drift)Drift detected (drift only)
drift activa --include-drops y --include-table-drops por defecto, porque su trabajo es reportar toda diferencia. El script que escribe es un reporte: no lo canalice a apply sin leerlo. drift enables --include-drops and --include-table-drops by default, because its job is to report every difference. The script it writes is a report; do not pipe it into apply without reading it.
09

Herramienta hermana — SyncJobCompanion tool — SyncJob

SQLDiff mueve la estructura. SyncJob mueve los datos. Primero la forma, después las filas.

SQLDiff moves the structure. SyncJob moves the data. Structure first, then the rows.

# la estructura, después las filasthe structure, then the rows
sqldiff deploy --source-conn "$DEV" --target-conn "$WAREHOUSE"
SyncJob.exe run -c appsettings.json -s SalesSync

# o poner drift como compuerta delante de la corrida nocturnaor put drift as a gate in front of the nightly run
sqldiff drift --source "…" --target "…" || exit 1
SyncJob.exe run -c appsettings.json --all

Una carga masiva hacia un destino cuya estructura cambió va a fallar de todos modos — y falla más claramente acá. Verificar la forma cuesta segundos.

A bulk load into a destination whose structure has drifted is going to fail anyway — and it fails more clearly here. Checking the shape costs seconds.

Las tres herramientas de bases de PeopleWorks: guía de DBFSync · SQLDiff · guía de SyncJob

The three PeopleWorks database tools: DBFSync guide · SQLDiff · SyncJob guide

10

ChuletaCheat sheet

Todos los comandos y todas las opciones.

Every command and every option.

ComandoCommand Aliases Qué haceWhat it does
sqldiff --help-hLista de comandos y opcionesCommand and option list
sqldiff --version-vVersiónVersion
check-conncheck-connectionVerifica una conexiónVerifies a connection
extractGuiona una base a .sql / .jsonScripts a database to .sql / .json
diffEscribe el script de migración; no aplicaWrites the migration script; applies nothing
driftComo diff; sale con 2 si difierenLike diff; exits 2 when they differ
applyCorre un script en una transacciónRuns a script in one transaction
deploydelta-applydiff + apply
syncIgual que deploy, con --apply explícitoSame as deploy, with an explicit --apply
OpciónOption Qué haceWhat it does
--conn · --connectionConexión única. Acepta env:NOMBRESingle connection. Accepts env:NAME
--conn-fileArchivo con la cadena de conexiónFile holding the connection string
--source-conn · --target-connConexión de cada lado (-conn-file también)Each side's connection (-conn-file too)
--source-snapshot · --target-snapshotUsar un .json en vez de una conexiónUse a .json instead of a connection
--out <PATH>Script de salida. Default schema.sqlOutput script. Defaults to schema.sql
--json <PATH>Snapshot JSON de extractJSON snapshot from extract
--script <PATH>Script a ejecutar con applyScript for apply to run
--log <PATH>Bitácora de la aplicaciónAudit log of the apply
--include · --excludeFiltros [tipo:]glob, separados por comas[type:]glob filters, comma-separated
--include-dropsPermite borrar objetos que solo existen en el destinoAllows dropping objects that exist only on the target
--include-table-dropsPermite borrar tablas enterasAllows dropping whole tables
--allow-table-rebuildPermite reconstruir una tabla cuando un ALTER no alcanzaAllows a table rebuild when an ALTER cannot do it
--add-onlySolo agrega lo que faltaOnly adds what is missing
--applyCon sync: aplica de verdadWith sync: actually apply
--dry-runMuestra lo que haría sin escribirShows what it would do without writing
--no-transactionNo envolver la aplicación en una transacciónDo not wrap the apply in a transaction
--timeout-seconds <N>Timeout por lote. Default 120Per-batch timeout. Defaults to 120