Rules¶
The following rules are available in this create. This list is generated from the rules module in the source code and can be turned on or off and configured in the config file.
Rule Index¶
| Rule Code | Rule Name | Description |
|---|---|---|
| AL01 | aliasing.table | Implicit/explicit aliasing of table. |
| AL02 | aliasing.column | Implicit/explicit aliasing of columns. |
| AL03 | aliasing.expression | Column expression without alias. Use explicit AS clause. |
| AL04 | aliasing.unique.table | Table aliases should be unique within each clause. |
| AL05 | aliasing.unused | Tables should not be aliased if that alias is not used. |
| AL06 | aliasing.length | Identify aliases in from clause and join conditions |
| AL07 | aliasing.forbid | Avoid table aliases in from clauses and join conditions. |
| AL08 | aliasing.unique.column | Column aliases should be unique within each clause. |
| AL09 | aliasing.self_alias.column | Find self-aliased columns and fix them |
| AM01 | ambiguous.distinct | Ambiguous use of 'DISTINCT' in a 'SELECT' statement with 'GROUP BY'. |
| AM02 | ambiguous.union | Look for UNION keyword not immediately followed by DISTINCT or ALL |
| AM03 | ambiguous.order_by | Ambiguous ordering directions for columns in order by clause. |
| AM04 | ambiguous.column_count | Outermost query should produce known number of columns. |
| AM05 | ambiguous.join | Join clauses should be fully qualified. |
| AM06 | ambiguous.column_references | Inconsistent column references in 'GROUP BY/ORDER BY' clauses. |
| AM07 | ambiguous.set_columns | All queries in set expression should return the same number of columns. |
| CP01 | capitalisation.keywords | Inconsistent capitalisation of keywords. |
| CP02 | capitalisation.identifiers | Inconsistent capitalisation of unquoted identifiers. |
| CP03 | capitalisation.functions | Inconsistent capitalisation of function names. |
| CP04 | capitalisation.literals | Inconsistent capitalisation of boolean/null literal. |
| CP05 | capitalisation.types | Inconsistent capitalisation of datatypes. |
| CV01 | convention.not_equal | Consistent usage of != or <> for "not equal to" operator. |
| CV02 | convention.coalesce | Use 'COALESCE' instead of 'IFNULL' or 'NVL'. |
| CV03 | convention.select_trailing_comma | Trailing commas within select clause |
| CV04 | convention.count_rows | Use consistent syntax to express "count number of rows". |
| CV05 | convention.is_null | Relational operators should not be used to check for NULL values. |
| CV06 | convention.terminator | Statements must end with a semi-colon. |
| CV07 | convention.statement_brackets | Top-level statements should not be wrapped in brackets. |
| CV08 | convention.left_join | Use LEFT JOIN instead of RIGHT JOIN. |
| CV09 | convention.blocked_words | Block a list of configurable words from being used. |
| CV10 | convention.quoted_literals | Consistent usage of preferred quotes for quoted literals. |
| CV11 | convention.casting_style | Enforce consistent type casting style. |
| JJ01 | jinja.padding | Jinja tags should have a single whitespace on either side. |
| LT01 | layout.spacing | Inappropriate Spacing. |
| LT02 | layout.indent | Incorrect Indentation. |
| LT03 | layout.operators | Operators should follow a standard for being before/after newlines. |
| LT04 | layout.commas | Leading/Trailing comma enforcement. |
| LT05 | layout.long_lines | Line is too long. |
| LT06 | layout.functions | Function name not immediately followed by parenthesis. |
| LT07 | layout.cte_bracket | 'WITH' clause closing bracket should be on a new line. |
| LT08 | layout.cte_newline | Blank line expected but not found after CTE closing bracket. |
| LT09 | layout.select_targets | Select targets should be on a new line unless there is only one select target. |
| LT10 | layout.select_modifiers | 'SELECT' modifiers (e.g. 'DISTINCT') must be on the same line as 'SELECT'. |
| LT11 | layout.set_operators | Set operators should be surrounded by newlines. |
| LT12 | layout.end_of_file | Files must end with a single trailing newline. |
| LT13 | layout.start_of_file | Files must not begin with newlines or whitespace. |
| LT15 | layout.newlines | Too many consecutive blank lines. |
| RF01 | references.from | References cannot reference objects not present in 'FROM' clause. |
| RF02 | references.qualification | References should be qualified if select has more than one referenced table/view. |
| RF03 | references.consistent | References should be consistent in statements with a single table. |
| RF04 | references.keywords | Keywords should not be used as identifiers. |
| RF05 | references.special_chars | Do not use special characters in identifiers. |
| RF06 | references.quoting | Unnecessary quoted identifier. |
| ST01 | structure.else_null | Do not specify 'else null' in a case when statement (redundant). |
| ST02 | structure.simple_case | Unnecessary 'CASE' statement. |
| ST03 | structure.unused_cte | Query defines a CTE (common-table expression) but does not use it. |
| ST04 | structure.nested_case | Nested CASE statement in ELSE clause could be flattened. |
| ST05 | structure.subquery | Join/From clauses should not contain subqueries. Use CTEs instead. |
| ST06 | structure.column_order | Select wildcards then simple targets before calculations and aggregates. |
| ST07 | structure.using | Prefer specifying join keys instead of using USING. |
| ST08 | structure.distinct | Looking for DISTINCT before a bracket |
| ST09 | structure.join_condition_order | Joins should list the table referenced earlier/later first. |
Rule Details¶
aliasing.table¶
Implicit/explicit aliasing of table.
Code: AL01
Groups: all, aliasing
Fixable: Yes
Anti-pattern
In this example, the alias voo is implicit.
Best practice
Add AS to make the alias explicit.
aliasing.column¶
Implicit/explicit aliasing of columns.
Code: AL02
Groups: all, core, aliasing
Fixable: Yes
Anti-pattern
In this example, the alias for column a is implicit.
Best practice
Add the AS keyword to make the alias explicit.
aliasing.expression¶
Column expression without alias. Use explicit AS clause.
Code: AL03
Groups: all, core, aliasing
Fixable: No
Anti-pattern
In this example, there is no alias for both sums.
Best practice
Add aliases.
aliasing.unique.table¶
Table aliases should be unique within each clause.
Code: AL04
Groups: all, core, aliasing
Fixable: No
Anti-pattern
In this example, the alias t is reused for two different tables:
SELECT
t.a,
t.b
FROM foo AS t, bar AS t
-- This can also happen when using schemas where the
-- implicit alias is the table name:
SELECT
a,
b
FROM
2020.foo,
2021.foo
Best practice
Make all tables have a unique alias.
SELECT
f.a,
b.b
FROM foo AS f, bar AS b
-- Also use explicit aliases when referencing two tables
-- with the same name from two different schemas.
SELECT
f1.a,
f2.b
FROM
2020.foo AS f1,
2021.foo AS f2
aliasing.unused¶
Tables should not be aliased if that alias is not used.
Code: AL05
Groups: all, core, aliasing
Fixable: Yes
Anti-pattern
In this example, alias zoo is not used.
Best practice
Use the alias or remove it. An unused alias makes code harder to read without changing any functionality.
aliasing.length¶
Identify aliases in from clause and join conditions
Code: AL06
Groups: all, core, aliasing
Fixable: No
Anti-pattern
In this example, alias o is used for the orders table.
Best practice
Avoid aliases. Avoid short aliases when aliases are necessary.
See also: Rule_AL07.
SELECT
SUM(orders.amount) as order_amount,
FROM orders
SELECT
replacement_orders.amount,
previous_orders.amount
FROM
orders AS replacement_orders
JOIN
orders AS previous_orders
ON replacement_orders.id = previous_orders.replacement_id
aliasing.forbid¶
Avoid table aliases in from clauses and join conditions.
Code: AL07
Groups: all, aliasing
Fixable: Yes
Anti-pattern
In this example, alias o is used for the orders table, and c is used for customers table.
SELECT
COUNT(o.customer_id) as order_amount,
c.name
FROM orders as o
JOIN customers as c on o.id = c.user_id
Best practice
Avoid aliases.
SELECT
COUNT(orders.customer_id) as order_amount,
customers.name
FROM orders
JOIN customers on orders.id = customers.user_id
-- Self-join will not raise issue
SELECT
table1.a,
table_alias.b,
FROM
table1
LEFT JOIN table1 AS table_alias ON
table1.foreign_key = table_alias.foreign_key
aliasing.unique.column¶
Column aliases should be unique within each clause.
Code: AL08
Groups: all, core, aliasing
Fixable: No
Anti-pattern
In this example, alias o is used for the orders table, and c is used for customers table.
SELECT
COUNT(o.customer_id) as order_amount,
c.name
FROM orders as o
JOIN customers as c on o.id = c.user_id
Best practice
Avoid aliases.
SELECT
COUNT(orders.customer_id) as order_amount,
customers.name
FROM orders
JOIN customers on orders.id = customers.user_id
-- Self-join will not raise issue
SELECT
table1.a,
table_alias.b,
FROM
table1
LEFT JOIN table1 AS table_alias ON
table1.foreign_key = table_alias.foreign_key
aliasing.self_alias.column¶
Find self-aliased columns and fix them
Code: AL09
Groups: all, core, aliasing
Fixable: No
Anti-pattern
Aliasing the column to itself.
Best practice
Not to use alias to rename the column to its original name. Self-aliasing leads to redundant code without changing any functionality.
ambiguous.distinct¶
Ambiguous use of 'DISTINCT' in a 'SELECT' statement with 'GROUP BY'.
Code: AM01
Groups: all, core, ambiguous
Fixable: No
Anti-pattern
DISTINCT and GROUP BY are conflicting.
Best practice
Remove DISTINCT or GROUP BY. In our case, removing GROUP BY is better.
ambiguous.union¶
Look for UNION keyword not immediately followed by DISTINCT or ALL
Code: AM02
Groups: all, core, ambiguous
Fixable: Yes
Anti-pattern
In this example, UNION DISTINCT should be preferred over UNION, because explicit is better than implicit.
Best practice
Specify DISTINCT or ALL after UNION (note that DISTINCT is the default behavior).
Dialects where this rule is skipped: bigquery, postgres, snowflake, clickhouse, sparksql, duckdb
ambiguous.order_by¶
Ambiguous ordering directions for columns in order by clause.
Code: AM03
Groups: all, ambiguous
Fixable: Yes
Anti-pattern
In this example, the ORDER BY clause is ambiguous because some columns are explicitly ordered, while others are not.
Best practice
If any columns in the ORDER BY clause specify ASC or DESC, they should all do so.
ambiguous.column_count¶
Outermost query should produce known number of columns.
Code: AM04
Groups: all, ambiguous
Fixable: No
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 columnsa,b, andc, the actual columns returned will be wrong/different if columns are added to or deleted from the input table. UNIONandDIFFERENCEclauses require the inputs have the same number of columns (and compatible types).JOINqueries may break due to new column name conflicts, e.g. the query references a columncwhich 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 *
Best practice
Somewhere along the "path" to the source data, specify columns explicitly.
ambiguous.join¶
Join clauses should be fully qualified.
Code: AM05
Groups: all, ambiguous
Fixable: Yes
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.
fully_qualify_join_types: Which types of JOIN clauses should be fully qualified? Must be one of['inner', 'outer', 'both'].
Anti-pattern
A join is used without specifying the kind of join.
Best practice
Use INNER JOIN rather than JOIN.
ambiguous.column_references¶
Inconsistent column references in 'GROUP BY/ORDER BY' clauses.
Code: AM06
Groups: all, core, ambiguous
Fixable: No
Anti-pattern
In this example, the ORRDER BY clause mixes explicit and implicit order by column references.
Best practice
If any columns in the ORDER BY clause specify ASC or DESC, they should all do so.
ambiguous.set_columns¶
All queries in set expression should return the same number of columns.
Code: AM07
Groups: all, ambiguous
Fixable: No
Anti-pattern
When writing set expressions, all queries must return the same number of columns.
Best practice
Always specify columns when writing set queries and ensure that they all seleect same number of columns.
capitalisation.keywords¶
Inconsistent capitalisation of keywords.
Code: CP01
Groups: all, core, capitalisation
Fixable: Yes
Anti-pattern
In this example, select is in lower-case whereas FROM is in upper-case.
Best practice
Make all keywords either in upper-case or in lower-case.
capitalisation.identifiers¶
Inconsistent capitalisation of unquoted identifiers.
Code: CP02
Groups: all, core, capitalisation
Fixable: Yes
Anti-pattern
In this example, unquoted identifier a is in lower-case but B is in upper-case.
Best practice
Ensure all unquoted identifiers are either in upper-case or in lower-case.
capitalisation.functions¶
Inconsistent capitalisation of function names.
Code: CP03
Groups: all, core, capitalisation
Fixable: Yes
Anti-pattern
In this example, the two SUM functions don’t have the same capitalisation.
Best practice
Make the case consistent.
capitalisation.literals¶
Inconsistent capitalisation of boolean/null literal.
Code: CP04
Groups: all, core, capitalisation
Fixable: Yes
Anti-pattern
In this example, null and false are in lower-case whereas TRUE is in upper-case.
Best practice
Ensure all literal null/true/false literals are consistently upper or lower case
capitalisation.types¶
Inconsistent capitalisation of datatypes.
Code: CP05
Groups: all, core, capitalisation
Fixable: Yes
Anti-pattern
In this example, int and unsigned are in lower-case whereas VARCHAR is in upper-case.
Best practice
Ensure all datatypes are consistently upper or lower case
convention.not_equal¶
Consistent usage of != or <> for "not equal to" operator.
Code: CV01
Groups: all, convention
Fixable: Yes
Anti-pattern
Consistent usage of != or <> for "not equal to" operator.
Best practice
Ensure all "not equal to" comparisons are consistent, not mixing != and <>.
convention.coalesce¶
Use 'COALESCE' instead of 'IFNULL' or 'NVL'.
Code: CV02
Groups: all, convention
Fixable: No
Anti-pattern
IFNULL or NVL are used to fill NULL values.
Best practice
Use COALESCE instead. COALESCE is universally supported, whereas Redshift doesn’t support IFNULL and BigQuery doesn’t support NVL. Additionally, COALESCE is more flexible and accepts an arbitrary number of arguments.
convention.select_trailing_comma¶
Trailing commas within select clause
Code: CV03
Groups: all, core, convention
Fixable: No
Anti-pattern
In this example, the last selected column has a trailing comma.
Best practice
Remove the trailing comma.
convention.count_rows¶
Use consistent syntax to express "count number of rows".
Code: CV04
Groups: all, core, convention
Fixable: No
Anti-pattern
In this example, count(1) is used to count the number of rows in a table.
Best practice
Use count(*) unless specified otherwise by config prefer_count_1, or prefer_count_0 as preferred.
convention.is_null¶
Relational operators should not be used to check for NULL values.
Code: CV05
Groups: all, core, convention
Fixable: No
Anti-pattern
In this example, the = operator is used to check for NULL values.
Best practice
Use IS or IS NOT to check for NULL values.
convention.terminator¶
Statements must end with a semi-colon.
Code: CV06
Groups: all, convention
Fixable: Yes
Anti-pattern
A statement is not immediately terminated with a semi-colon. The • represents space.
Best practice
Immediately terminate the statement with a semi-colon.
convention.statement_brackets¶
Top-level statements should not be wrapped in brackets.
Code: CV07
Groups: all, convention
Fixable: Yes
Anti-pattern
A top-level statement is wrapped in brackets.
(SELECT
foo
FROM bar)
-- This also applies to statements containing a sub-query.
(SELECT
foo
FROM (SELECT * FROM bar))
Best practice
Don’t wrap top-level statements in brackets.
SELECT
foo
FROM bar
-- Likewise for statements containing a sub-query.
SELECT
foo
FROM (SELECT * FROM bar)
convention.left_join¶
Use LEFT JOIN instead of RIGHT JOIN.
Code: CV08
Groups: all, convention
Fixable: No
Anti-pattern
RIGHT JOIN is used.
Best practice
Refactor and use LEFT JOIN instead.
convention.blocked_words¶
Block a list of configurable words from being used.
Code: CV09
Groups: all, convention
Fixable: No
This generic rule can be useful to prevent certain keywords, functions, or objects from being used. Only whole words can be blocked, not phrases, nor parts of words.
This block list is case insensitive.
Example use cases
- We prefer
BOOLoverBOOLEANand there is no existing rule to enforce this. Until such a rule is written, we can addBOOLEANto the deny list to cause a linting error to flag this. - We have deprecated a schema/table/function and want to prevent it being used
in future. We can add that to the denylist and then add a
-- noqa: CV09for the few exceptions that still need to be in the code base for now.
Anti-pattern
If the blocked_words config is set to deprecated_table,bool then the following will flag:
Best practice
Do not used any blocked words.
convention.quoted_literals¶
Consistent usage of preferred quotes for quoted literals.
Code: CV10
Groups: all, convention
Fixable: Yes
Anti-pattern
Best practice
Ensure all quoted literals use preferred quotes, unless escaping can be reduced by using alternate quotes.
select
"abc",
"abc",
'"',
"abc" = "abc"
from foo
```P
### convention.casting_style
Enforce consistent type casting style.
**Code:** `CV11`
**Groups:** `all`, `convention`
**Fixable:** Yes
**Anti-pattern**
Using a mixture of `CONVERT`, `::`, and `CAST` when `preferred_type_casting_style` config is set to `consistent` (default).
```sql
SELECT
CONVERT(int, 1) AS bar,
100::int::text,
CAST(10 AS text) AS coo
FROM foo;
Best Practice
Use a consistent type casting style.
jinja.padding¶
Jinja tags should have a single whitespace on either side.
Code: JJ01
Groups: all, core, jinja
Fixable: Yes
Anti-pattern
Jinja tags with either no whitespace or very long whitespace are hard to read.
Best practice
A single whitespace surrounding Jinja tags, alternatively longer gaps containing newlines are acceptable.
layout.spacing¶
Inappropriate Spacing.
Code: LT01
Groups: all, core, layout
Fixable: Yes
Anti-pattern
In this example, spacing is all over the place and is represented by •.
Best practice
- Unless an indent or preceding a comment, whitespace should be a single space.
- There should also be no trailing whitespace at the ends of lines.
- There should be a space after USING so that it’s not confused for a function.
layout.indent¶
Incorrect Indentation.
Code: LT02
Groups: all, core, layout
Fixable: Yes
Anti-pattern
The • character represents a space and the → character represents a tab.
In this example, the third line contains five spaces instead of four and
the second line contains two spaces and one tab.
Best practice
Change the indentation to use a multiple of four spaces. This example also assumes that the indent_unit config value is set to space. If it had instead been set to tab, then the indents would be tabs instead.
layout.operators¶
Operators should follow a standard for being before/after newlines.
Code: LT03
Groups: all, layout
Fixable: Yes
Anti-pattern
In this example, if line_position = leading (or unspecified, as is the default), then the operator + should not be at the end of the second line.
Best practice
If line_position = leading (or unspecified, as this is the default), place the operator after the newline.
If line_position = trailing, place the operator before the newline.
layout.commas¶
Leading/Trailing comma enforcement.
Code: LT04
Groups: all, layout
Fixable: Yes
Anti-pattern
There is a mixture of leading and trailing commas.
Best practice
By default, sqruff prefers trailing commas. However it is configurable for leading commas. The chosen style must be used consistently throughout your SQL.
SELECT
a,
b,
c
FROM foo
-- Alternatively, set the configuration file to 'leading'
-- and then the following would be acceptable:
SELECT
a
, b
, c
FROM foo
layout.long_lines¶
Line is too long.
Code: LT05
Groups: all, core, layout
Fixable: Yes
Anti-pattern
In this example, the line is too long.
SELECT
my_function(col1 + col2, arg2, arg3) over (partition by col3, col4 order by col5 rows between unbounded preceding and current row) as my_relatively_long_alias,
my_other_function(col6, col7 + col8, arg4) as my_other_relatively_long_alias,
my_expression_function(col6, col7 + col8, arg4) = col9 + col10 as another_relatively_long_alias
FROM my_table
Best practice
Wraps the line to be within the maximum line length.
SELECT
my_function(col1 + col2, arg2, arg3)
over (
partition by col3, col4
order by col5 rows between unbounded preceding and current row
)
as my_relatively_long_alias,
my_other_function(col6, col7 + col8, arg4)
as my_other_relatively_long_alias,
my_expression_function(col6, col7 + col8, arg4)
= col9 + col10 as another_relatively_long_alias
FROM my_table
layout.functions¶
Function name not immediately followed by parenthesis.
Code: LT06
Groups: all, core, layout
Fixable: Yes
Anti-pattern
In this example, there is a space between the function and the parenthesis.
Best practice
Remove the space between the function and the parenthesis.
layout.cte_bracket¶
'WITH' clause closing bracket should be on a new line.
Code: LT07
Groups: all, core, layout
Fixable: No
Anti-pattern
In this example, the closing bracket is on the same line as CTE.
Best practice
Move the closing bracket on a new line.
layout.cte_newline¶
Blank line expected but not found after CTE closing bracket.
Code: LT08
Groups: all, core, layout
Fixable: Yes
Anti-pattern
There is no blank line after the CTE closing bracket. In queries with many CTEs, this hinders readability.
Best practice
Add a blank line.
layout.select_targets¶
Select targets should be on a new line unless there is only one select target.
Code: LT09
Groups: all, layout
Fixable: Yes
Anti-pattern
Multiple select targets on the same line.
Best practice
Multiple select targets each on their own line.
select
a,
b
from foo;
-- Single select target on the same line as the ``SELECT``
-- keyword.
SELECT a
FROM foo;
-- When select targets span multiple lines, however they
-- can still be on a new line.
SELECT
SUM(
1 + SUM(
2 + 3
)
) AS col
FROM test_table;
layout.select_modifiers¶
'SELECT' modifiers (e.g. 'DISTINCT') must be on the same line as 'SELECT'.
Code: LT10
Groups: all, core, layout
Fixable: Yes
Anti-pattern
In this example, the DISTINCT modifier is on the next line after the SELECT keyword.
Best practice
Move the DISTINCT modifier to the same line as the SELECT keyword.
layout.set_operators¶
Set operators should be surrounded by newlines.
Code: LT11
Groups: all, core, layout
Fixable: Yes
Anti-pattern
In this example, UNION ALL is not on a line itself.
Best practice
Place UNION ALL on its own line.
layout.end_of_file¶
Files must end with a single trailing newline.
Code: LT12
Groups: all, core, layout
Fixable: Yes
Anti-pattern
The content in file does not end with a single trailing newline. The $ represents end of file.
SELECT
a
FROM foo$
-- Ending on an indented line means there is no newline
-- at the end of the file, the • represents space.
SELECT
••••a
FROM
••••foo
••••$
-- Ending on a semi-colon means the last line is not a
-- newline.
SELECT
a
FROM foo
;$
-- Ending with multiple newlines.
SELECT
a
FROM foo
$
Best practice
Add trailing newline to the end. The $ character represents end of file.
SELECT
a
FROM foo
$
-- Ensuring the last line is not indented so is just a
-- newline.
SELECT
••••a
FROM
••••foo
$
-- Even when ending on a semi-colon, ensure there is a
-- newline after.
SELECT
a
FROM foo
;
$
layout.start_of_file¶
Files must not begin with newlines or whitespace.
Code: LT13
Groups: all, layout
Fixable: Yes
Anti-pattern
The file begins with newlines or whitespace. The ^ represents the beginning of the file.
^
SELECT
a
FROM foo
-- Beginning on an indented line is also forbidden,
-- (the • represents space).
••••SELECT
••••a
FROM
••••foo
Best practice
Start file on either code or comment. (The ^ represents the beginning of the file.)
^SELECT
a
FROM foo
-- Including an initial block comment.
^/*
This is a description of my SQL code.
*/
SELECT
a
FROM
foo
-- Including an initial inline comment.
^--This is a description of my SQL code.
SELECT
a
FROM
foo
layout.newlines¶
Too many consecutive blank lines.
Code: LT15
Groups: all, layout
Fixable: Yes Anti-pattern
In this example, the maximum number of empty lines inside a statement is set to 0.
Best practice
references.from¶
References cannot reference objects not present in 'FROM' clause.
Code: RF01
Groups: all, core, references
Fixable: No
Anti-pattern
In this example, the reference vee has not been declared.
Best practice
Remove the reference.
Dialects where this rule is skipped: athena, redshift, bigquery, databricks, duckdb, sparksql
references.qualification¶
References should be qualified if select has more than one referenced table/view.
Code: RF02
Groups: all, references
Fixable: No
Anti-pattern
In this example, the reference vee has not been declared, and the variables a and b are potentially ambiguous.
Best practice
Add the references.
references.consistent¶
References should be consistent in statements with a single table.
Code: RF03
Groups: all, references
Fixable: Yes
Anti-pattern
In this example, only the field b is referenced.
Best practice
Add or remove references to all fields.
Dialects where this rule is skipped: bigquery, redshift
references.keywords¶
Keywords should not be used as identifiers.
Code: RF04
Groups: all, references
Fixable: No
Anti-pattern
In this example, SUM (a built-in function) is used as an alias.
Best practice
Avoid using keywords as the name of an alias.
references.special_chars¶
Do not use special characters in identifiers.
Code: RF05
Groups: all, references
Fixable: No
Anti-pattern
Using special characters within identifiers when creating or aliasing objects.
CREATE TABLE DBO.ColumnNames
(
[Internal Space] INT,
[Greater>Than] INT,
[Less<Than] INT,
Number# INT
)
Best practice
Identifiers should include only alphanumerics and underscores.
CREATE TABLE DBO.ColumnNames
(
[Internal_Space] INT,
[GreaterThan] INT,
[LessThan] INT,
NumberVal INT
)
references.quoting¶
Unnecessary quoted identifier.
Code: RF06
Groups: all, references
Fixable: Yes
Anti-pattern
In this example, a valid unquoted identifier, that is also not a reserved keyword, is needlessly quoted.
Best practice
Use unquoted identifiers where possible.
When prefer_quoted_identifiers = True, the quotes are always necessary, no matter if the identifier is valid, a reserved keyword, or contains special characters.
Note Note due to different quotes being used by different dialects supported by
SQLFluff, and those quotes meaning different things in different contexts, this mode is notsqlfluff fixcompatible.
Anti-pattern
In this example, a valid unquoted identifier, that is also not a reserved keyword, is required to be quoted.
Best practice
Use quoted identifiers.
structure.else_null¶
Do not specify 'else null' in a case when statement (redundant).
Code: ST01
Groups: all, structure
Fixable: No
Anti-pattern
select
case
when name like '%cat%' then 'meow'
when name like '%dog%' then 'woof'
else null
end
from x
Best practice
Omit else null
structure.simple_case¶
Unnecessary 'CASE' statement.
Code: ST02
Groups: all, structure
Fixable: No
Anti-pattern
CASE statement returns booleans.
select
case
when fab > 0 then true
else false
end as is_fab
from fancy_table
-- This rule can also simplify CASE statements
-- that aim to fill NULL values.
select
case
when fab is null then 0
else fab
end as fab_clean
from fancy_table
-- This also covers where the case statement
-- replaces NULL values with NULL values.
select
case
when fab is null then null
else fab
end as fab_clean
from fancy_table
Best practice
Reduce to WHEN condition within COALESCE function.
select
coalesce(fab > 0, false) as is_fab
from fancy_table
-- To fill NULL values.
select
coalesce(fab, 0) as fab_clean
from fancy_table
-- NULL filling NULL.
select fab as fab_clean
from fancy_table
structure.unused_cte¶
Query defines a CTE (common-table expression) but does not use it.
Code: ST03
Groups: all, core, structure
Fixable: No
Anti-pattern
Defining a CTE that is not used by the query is harmless, but it means the code is unnecessary and could be removed.
Best practice
Remove unused CTEs.
structure.nested_case¶
Nested CASE statement in ELSE clause could be flattened.
Code: ST04
Groups: all, structure
Fixable: Yes
Anti-pattern¶
In this example, the outer CASE's ELSE is an unnecessary, nested CASE.
SELECT
CASE
WHEN species = 'Cat' THEN 'Meow'
ELSE
CASE
WHEN species = 'Dog' THEN 'Woof'
END
END as sound
FROM mytable
Best practice¶
Move the body of the inner CASE to the end of the outer one.
SELECT
CASE
WHEN species = 'Cat' THEN 'Meow'
WHEN species = 'Dog' THEN 'Woof'
END AS sound
FROM mytable
structure.subquery¶
Join/From clauses should not contain subqueries. Use CTEs instead.
Code: ST05
Groups: all, structure
Fixable: Yes
Anti-pattern¶
Join is a sub query in a FROM clause. This can make the query harder to read and maintain.
Best practice¶
Use a Common Table Expression (CTE) to define the subquery and then join it to the main query.
structure.column_order¶
Select wildcards then simple targets before calculations and aggregates.
Code: ST06
Groups: all, structure
Fixable: Yes
Anti-pattern
Best practice
Order select targets in ascending complexity
structure.using¶
Prefer specifying join keys instead of using USING.
Code: ST07
Groups: all, structure
Fixable: Yes
Anti-pattern
Best practice
Specify the keys directly
Dialects where this rule is skipped:clickhouse
structure.distinct¶
Looking for DISTINCT before a bracket
Code: ST08
Groups: all, core, structure
Fixable: No
Anti-pattern
In this example, parentheses are not needed and confuse DISTINCT with a function. The parentheses can also be misleading about which columns are affected by the DISTINCT (all the columns!).
Best practice
Remove parentheses to be clear that the DISTINCT applies to both columns.
structure.join_condition_order¶
Joins should list the table referenced earlier/later first.
Code: ST09
Groups: all, structure
Fixable: No
Anti-pattern
In this example, the tables that were referenced later are listed first
and the preferred_first_table_in_join_clause configuration
is set to earlier.
select
foo.a,
foo.b,
bar.c
from foo
left join bar
-- This subcondition does not list
-- the table referenced earlier first:
on bar.a = foo.a
-- Neither does this subcondition:
and bar.b = foo.b
Best practice
List the tables that were referenced earlier first.