Skip to content

Ambiguous Rules

This section contains 9 rule(s) related to ambiguous.

Rule Summary

CodeNameAliasesFix Compatible
AM01ambiguous.distinctL021
AM02ambiguous.unionL033
AM03ambiguous.order_byL037
AM04ambiguous.column_countL044
AM05ambiguous.joinL051
AM06ambiguous.column_referencesL054
AM07ambiguous.set_columnsL068
AM08ambiguous.join_condition-
AM09ambiguous.order_by_limit-

AM01: ambiguous.distinct

Ambiguous use of DISTINCT in a SELECT statement with GROUP BY.

PropertyValue
Nameambiguous.distinct
AliasesL021
Groupsall, core, ambiguous
Auto-fixableNo ❌

When using GROUP BY a DISTINCT clause should not be necessary as every non-distinct SELECT clause must be included in the GROUP BY clause.

Anti-pattern

DISTINCT and GROUP BY are conflicting.

sql
SELECT DISTINCT
    a
FROM foo
GROUP BY a

Best practice

Remove DISTINCT or GROUP BY. In our case, removing GROUP BY is better.

sql
SELECT DISTINCT
    a
FROM foo

**Groups**: `all`, `core`, `ambiguous``

AM02: ambiguous.union

UNION [DISTINCT|ALL] is preferred over just UNION.

PropertyValue
Nameambiguous.union
AliasesL033
Groupsall, core, ambiguous
Auto-fixableYes ✅

NOTE

This rule is only enabled for dialects that support UNION and UNION DISTINCT (ansi, bigquery, clickhouse, databricks, db2, hive, mysql, redshift, snowflake, and trino).

Anti-pattern

In this example, UNION DISTINCT should be preferred over UNION, because explicit is better than implicit.

sql
SELECT a, b FROM table_1
UNION
SELECT a, b FROM table_2

Best practice

Specify DISTINCT or ALL after UNION (note that DISTINCT is the default behavior).

sql
SELECT a, b FROM table_1
UNION DISTINCT
SELECT a, b FROM table_2

AM03: ambiguous.order_by

Ambiguous ordering directions for columns in order by clause.

PropertyValue
Nameambiguous.order_by
AliasesL037
Groupsall, ambiguous
Auto-fixableYes ✅

Anti-pattern

sql
SELECT
    a, b
FROM foo
ORDER BY a, b DESC

Best practice

If any columns in the ORDER BY clause specify ASC or DESC, they should all do so.

sql
SELECT
    a, b
FROM foo
ORDER BY a ASC, b DESC

AM04: ambiguous.column_count

Query produces an unknown number of result columns.

PropertyValue
Nameambiguous.column_count
AliasesL044
Groupsall, ambiguous
Auto-fixableNo ❌

Anti-pattern

Querying all columns using * produces a query result where the number or ordering of columns changes if the upstream table's schema changes. This should generally be avoided because it can cause slow performance, cause important schema changes to go undetected, or break production code. For example:

  • If a query does SELECT t.* and is expected to return columns a, b, and c, the actual columns returned will be wrong/different if columns are added to or deleted from the input table.
  • UNION and DIFFERENCE clauses require the inputs have the same number of columns (and compatible types).
  • JOIN queries may break due to new column name conflicts, e.g. the query references a column c which initially existed in only one input table but a column of the same name is added to another table.
  • CREATE TABLE (<<column schema>>) AS SELECT *
sql
WITH cte AS (
    SELECT * FROM foo
)

SELECT * FROM cte
UNION
SELECT a, b FROM t

Best practice

Somewhere along the "path" to the source data, specify columns explicitly.

sql
WITH cte AS (
    SELECT * FROM foo
)

SELECT a, b FROM cte
UNION
SELECT a, b FROM t

AM05: ambiguous.join

Join clauses should be fully qualified.

PropertyValue
Nameambiguous.join
AliasesL051
Groupsall, ambiguous
Auto-fixableYes ✅

By default this rule is configured to enforce fully qualified INNER JOIN clauses, but not [LEFT/RIGHT/FULL] OUTER JOIN. If you prefer a stricter lint then this is configurable.

Anti-pattern

A join is used without specifying the kind of join.

sql
SELECT
    foo
FROM bar
JOIN baz;

Best practice

Use INNER JOIN rather than JOIN.

sql
SELECT
    foo
FROM bar
INNER JOIN baz;

Configuration

OptionDescription
fully_qualify_join_typesWhich types of JOIN clauses should be fully qualified? Must be one of ['inner', 'outer', 'both'].

AM06: ambiguous.column_references

Inconsistent column references in GROUP BY/ORDER BY clauses.

PropertyValue
Nameambiguous.column_references
AliasesL054
Groupsall, core, ambiguous
Auto-fixableNo ❌

NOTE

ORDER BY clauses from WINDOW clauses are ignored by this rule.

Anti-pattern

A mix of implicit and explicit column references are used in a GROUP BY clause.

sql
SELECT
    foo,
    bar,
    sum(baz) AS sum_value
FROM fake_table
GROUP BY
    foo, 2;

-- The same also applies to column
-- references in ORDER BY clauses.

SELECT
    foo,
    bar
FROM fake_table
ORDER BY
    1, bar;

Best practice

Reference all GROUP BY/ORDER BY columns either by name or by position.

sql
-- GROUP BY: Explicit
SELECT
    foo,
    bar,
    sum(baz) AS sum_value
FROM fake_table
GROUP BY
    foo, bar;

-- ORDER BY: Explicit
SELECT
    foo,
    bar
FROM fake_table
ORDER BY
    foo, bar;

-- GROUP BY: Implicit
SELECT
    foo,
    bar,
    sum(baz) AS sum_value
FROM fake_table
GROUP BY
    1, 2;

-- ORDER BY: Implicit
SELECT
    foo,
    bar
FROM fake_table
ORDER BY
    1, 2;

Configuration

OptionDescription
group_by_and_order_by_styleThe expectation for using explicit column name references or implicit positional references. Must be one of ['consistent', 'implicit', 'explicit'].

AM07: ambiguous.set_columns

Queries within set query produce different numbers of columns.

PropertyValue
Nameambiguous.set_columns
AliasesL068
Groupsall, ambiguous
Auto-fixableNo ❌

Anti-pattern

When writing set expressions, all queries must return the same number of columns.

sql
WITH cte AS (
    SELECT
        a,
        b
    FROM foo
)
SELECT * FROM cte
UNION
SELECT
    c,
    d,
    e
 FROM t

Best practice

Always specify columns when writing set queries and ensure that they all seleect same number of columns

sql
WITH cte AS (
    SELECT a, b FROM foo
)
SELECT
    a,
    b
FROM cte
UNION
SELECT
    c,
    d
FROM t

AM08: ambiguous.join_condition

Implicit cross join detected.

PropertyValue
Nameambiguous.join_condition
Groupsall, ambiguous
Auto-fixableYes ✅

Anti-pattern

Cross joins are valid, but rare in the wild - and more often created by mistake than on purpose. This rule catches situations where a cross join has been specified, but not explicitly and so the risk of a mistaken cross join is highly likely.

sql
SELECT
    foo
FROM bar
JOIN baz;

Best practice

Use CROSS JOIN.

sql
SELECT
    foo
FROM bar
CROSS JOIN baz;

AM09: ambiguous.order_by_limit

Use of LIMIT and OFFSET without ORDER BY may lead to non-deterministic results.

PropertyValue
Nameambiguous.order_by_limit
Groupsall, ambiguous
Auto-fixableNo ❌

When using LIMIT or OFFSET, it's generally recommended to include an ORDER BY clause to ensure deterministic results.

Anti-pattern

The following query has LIMIT and OFFSET without ORDER BY, which may return different results in successive executions.

sql
SELECT *
FROM foo
LIMIT 10 OFFSET 5;

Best practice

Include an ORDER BY clause:

sql
SELECT *
FROM foo
ORDER BY id
LIMIT 10 OFFSET 5;

Released under the MIT License.