Semantic Diff
The diff command compares SQL files between git commits and reports semantic changes: tables added/removed, WHERE clauses dropped, JOIN types changed, columns added to SELECT.
Quick Start
# Compare main branch to current HEAD
lexega-sql diff main..HEAD models/ -r
# Compare specific commits
lexega-sql diff abc123..def456 models/ -r
# JSON output for CI/CD
lexega-sql diff main..HEAD -o json
# PostgreSQL projects
lexega-sql diff main..HEAD models/ -r --dialect postgresql
Comparison to git diff
git diff shows text changes:
- SELECT id, name FROM users WHERE active = true
+ SELECT id, name, email FROM users
Semantic diff reports structured change types:
File: models/users.sql
[HIGH] WHERE clause removed: `active = true`
[LOW] Column 'email' added
Detected Changes
| Change Type | Risk Level | Description |
|---|---|---|
WhereRemoved | HIGH | Query lost filtering — may return unbounded results |
WriteStatementBecameUnbounded | CRITICAL | DELETE/UPDATE lost WHERE clause |
ColumnAdded | LOW | New column in SELECT |
JoinTypeChanged | CRITICAL/HIGH/MEDIUM | CRITICAL: →CROSS JOIN; HIGH: LEFT→INNER; MEDIUM: other |
LimitRemoved | CRITICAL/HIGH | CRITICAL: multi-table (cartesian risk); HIGH: single-table |
TableAdded | LOW | New table in query |
ColumnRemoved | LOW | Column removed from SELECT |
CI/CD Integration
# GitHub Actions example
name: SQL Semantic Review
on: pull_request
jobs:
semantic-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history
- name: Semantic Diff
run: lexega-sql diff origin/main..HEAD models/ -r --policy .lexega/policy.yml --env prod --decision-out .lexega/
env:
LEXEGA_LICENSE_KEY: ${{ secrets.LEXEGA_LICENSE_KEY }}
# Exit code 2 = blocked by policy, 0 = passed
Jinja/dbt Support
The diff command renders Jinja templates on both sides before comparison, so semantic changes are computed on the rendered SQL, not template source.
Need Help?
Can't find what you're looking for? Check out our GitHub or reach out to support.