Skip to main content
A dedicated SQL analyzer (mehen-sql) introduces a new sql.* metric namespace tailored to standalone .sql files — ad-hoc queries, analytics models, migration scripts, stored-program bodies, DDL packages, and mixed scripts. It is backed by the sqruff dialect-aware SQL parser.
SQL files (.sql, .ddl, .dml) are analyzed automatically. The dialect is inferred from syntax hints with a reported confidence (sql.dialect.confidence), falling back to ANSI. mehen compiles ANSI, postgres, T-SQL, snowflake, bigquery, mysql, sqlite, oracle, clickhouse, redshift, sparksql, hive, athena, and db2.

Selecting a dialect

Dialect inference is a best-effort guess. To pin a file’s dialect deterministically, add an in-file directive on its own line, using the same syntax as SQLFluff’s in-file configuration:
When present, the directive overrides inference: sql.dialect.confidence is reported as 1.0, sql.dialect.directive_present is 1, and sql.dialect.is_<dialect> reflects the pinned dialect. mehen mirrors SQLFluff’s parsing of this directive:
  • Both -- sqlfluff:dialect:<name> and --sqlfluff:dialect:<name> (no space) are accepted. Whitespace around the dialect:<name> separator is ignored, but the sqlfluff: prefix itself must be exact.
  • The directive must start at the beginning of the line — an indented directive is ignored (this matches SQLFluff).
  • Only -- line comments are honored; block comments (/* sqlfluff:dialect:… */) are not.
  • If several directives appear, the last one wins.
  • An unknown dialect name (sql.dialect.unknown) or one not compiled into this build such as databricks, duckdb, or trino (sql.dialect.unsupported) emits a non-blocking warning and falls back to inference — it never aborts the analysis.
sqruff (mehen’s parser) does not itself consume SQLFluff in-file configuration — it silently ignores the directive (and older builds panic on some inline-config forms). mehen therefore parses the dialect directive itself and only ever hands sqruff a resolved, validated dialect. One intentional divergence from SQLFluff: SQLFluff matches dialect names case-sensitively, and so does mehen — -- sqlfluff:dialect:Postgres (capital P) is reported as an unknown dialect, exactly as SQLFluff would reject it.

Why SQL gets its own family

SQL should not be squeezed into the existing function/class-centric metric model. The dominant complexity mechanism in standalone SQL is relational/dataflow structure rather than imperative control flow:
  • Cyclomatic complexity is meaningful for procedural PL/SQL or T-SQL, but not for ordinary declarative SELECT-heavy files.
  • A SELECT with 10 joins and 5 CTEs may have no imperative branches while still being difficult to review.
  • Object-touch risk (DROP, TRUNCATE, MERGE without WHERE) often dominates “review burden” in migration scripts.

Metric namespaces

These sql.* keys are published today (raw metrics — research foundation §15): Procedural-SQL metrics (sql.procedural.* — cyclomatic/cognitive complexity for PL/SQL and T-SQL routines) remain on the roadmap.

Composite scores

All six explainable composite scores ship today (research foundation §8):
  • sql.structural_complexity — CTE depth, join count, subquery depth, CASE depth, window count, set op count.
  • sql.cognitive_complexity — SQL analogue of code cognitive complexity.
  • sql.review_burden_index — file-level rank (0–100) for likely PR review effort.
  • sql.change_risk_score — operational risk in migration scripts.
  • sql.maintainability_index — composite (0–100, higher is better) with band interpretation.
  • sql.modularity_health — CTE use ratio, fan-out, derived-table penalty (0–100; N/A without CTEs).

Prior art and scientific basis

The metric model is informed by the following work:
  • SonarQube PL/SQL and T-SQL — defines cyclomatic complexity for procedural blocks (anonymous blocks, procedures, triggers, loops, WHEN, IF/ELSIF, RAISE, AND/OR). PL/SQL docs · T-SQL docs.
  • SQLFluff and sqruff — dialect-aware parsing and linting; their structure rules (nested-CASE, unused-CTE, ambiguous-column-count, qualification, implicit cross-join) are reusable inspiration for metric contributors. SQLFluff docs · sqruff docs.
  • sqlfluff-complexity plugin — practical baseline for CPX-style metrics: CTE count, join count, nested subquery depth, CASE expressions, boolean operators, window functions, CTE dependency depth, set operations, derived tables. Repo.
  • Vashistha & Jain — Measuring Query Complexity in SQLShare Workload — frames query complexity as cognitive load on users authoring SQL, with operators / operands / runtime / Halstead-style measures. PDF.
  • Piattini & Martínez — Measuring for Database Programs Maintainability — early SQL maintainability measures with empirical validation. DOI.
  • Spider — text-to-SQL benchmark; its hardness criteria (number of components, selections, conditions, keywords like GROUP BY / nested subqueries / aggregators) align well with static query complexity features. arXiv:1809.08887 · Benchmark site.
See SQL metrics roadmap for the implementation phases.

See also