A Python port of sqlcheck — a tool that detects common SQL anti-patterns and suggests fixes.
sqlcheck-py parses your SQL with sqlglot
and walks the AST, so detection is more robust than pure regex matching and
works across many SQL dialects.
pip install -e .sqlcheckpy -f path/to/queries.sql
cat queries.sql | sqlcheckpy
sqlcheckpy -f queries.sql --risk medium --json
sqlcheckpy --list-checks| Flag | Description |
|---|---|
-f, --file PATH |
Read SQL from a file (defaults to stdin) |
-r, --risk LEVEL |
Minimum risk level: low, medium, high (default low) |
--checks LIST |
Comma-separated check names to run (default all) |
--list-checks |
Print all available checks and exit |
--dialect NAME |
sqlglot dialect (e.g. postgres, mysql, tsql) |
--no-color |
Disable ANSI colors |
--json |
Emit findings as JSON |
-v, --verbose |
Include detailed remediation text |
0— no issues at or above the configured risk level1— issues found2— usage / parse error
| Code | Name | Category | Risk |
|---|---|---|---|
| SC1001 | select_star | query | low |
| SC1002 | implicit_columns | query | medium |
| SC1003 | leading_wildcard | query | medium |
| SC1004 | having_without_group_by | query | low |
| SC1005 | null_comparison | query | high |
| SC1006 | order_by_rand | query | medium |
| SC1007 | delete_without_where | query | high |
| SC1008 | update_without_where | query | high |
| SC1009 | distinct_join | query | low |
| SC1010 | spaghetti_query | query | low |
| SC1011 | multi_valued_attribute | logical | medium |
| SC1012 | unused_cte | logical | low |
| SC2001 | generic_primary_key | logical | low |
| SC2002 | primary_key_not_specified | logical | medium |
| SC2003 | readable_passwords | application | high |
| SC2004 | recursive_dependency | logical | low |
| SC2005 | foreign_key_not_specified | logical | medium |
| SC2006 | entity_attribute_value | logical | medium |
| SC2007 | polymorphic_association | logical | low |
| SC2008 | multi_column_attribute | logical | medium |
| SC2009 | metadata_tribbles | logical | low |
| SC3001 | float_for_money | physical | high |
| SC3002 | values_in_definition | physical | low |
| SC3003 | files_are_physical | physical | medium |
| SC3004 | index_shotgun | physical | medium |
Cross-statement checks (currently index_shotgun) reason about all the
statements in a file, not just one. Everything else is per-statement.
Run sqlcheckpy --list-checks for the live list with descriptions.
pip install -e ".[dev]"
pytest