Sqlfluff the SQL Linter for Humans
sqlfluff.com
sqlfluff.com
Eg. some people like to align the clauses vertically and use a leading, not trailing, comma.
select a
, b
, count(*) as count
from table
where cond1
and cond2
group by a, b
order by count descI’ve done it this way before because it was quicker to edit, and and remove lines. But it’s not a format I’d particularly like to share with others because it looks weird.
I personally disobey both recommendations (I mean, the book is worth it for other reasons) but both those conventions are very commonly used.
I meant more the the "center" layout that the commenter above was describing, it'd seem quite laborious to maintain by hand in most environments, if not using a particular one that supports it out of the box.
select a
, b
, count(*) as count
from table
join table2 on table.key1 = table2.key1
and table.key2 = table2.key2
and DATEADD('day', 1, table.key3) = table2.key3
where cond1
and cond2
group by a, b
order by count desc
For me this lets me read the SQL query almost like a picture at first glance, identifying blocks of rivers as semantically connected groups of statements. Some SQL formatters out there love to put join clauses at the same indentation level as the join itself, drives me nuts.I will say my use case is probably different than others, I'm a Data Scientist so I write a ton of throwaway SQL and stuff that will only be seen by me. If I'm dealing with an existing SQL codebase or production stuff, definitely try to keep it more easily diff-able (like left justifying the keywords, really only caring about rivers in the join/where clauses), or just follow whatever patterns are already there.
select a
, b
, count(*) as count
from table
join table2
on table.key1 = table2.key1
and table.key2 = table2.key2
and DATEADD('day, 1, table.key3) = table2.key3
where cond1
and cond2
group by a, b
order by count desc
The largest difference is that the equal operators aren't aligned anymore, but on my opinion, aligning them is really not worth the cost. SELECT
a,
b,
count(*) as count
FROM
table
JOIN
table2
ON
table.key1 = table2.key1
AND
table.key2 = table2.key2
AND
-- 1 day apart
DATEADD('day', 1, table.key3) = table2.key3
WHERE
cond1
AND
cond2
AND
(
cond3
OR
cond4
)
GROUP BY
(a, b)
ORDER BY
count desc,
a asc
LIMIT
1000
;
Yes, that's a lot of whitespace, but it helps for complex queries.How much whitespace you need is completely dependent on what exactly you are writing.
I can give a few thoughts on why here:
- it doesn't work for collaborative efforts unless everyone is using the same linter or IDE with the same configuration. Not friendly to edits outside of that ecosystem (e.g. open source). - there are other ways of writing SQL (e.g. dbt style guide) which are still very readable while also being much faster to write by hand without the need for an auto-formatter. - some of these patterns such as the from and join indentations have nothing to do with readability and are purely stylistic. Nothing wrong with that, but there's nothing objectively better about this pattern - it just comes down to how you're used to reading SQL.
I can take a stab at justifying that - commas are used to form lists (eg, 1, 2, 3) and text (like "order by count") are supposed to be left justified.
You may be right that there are good reasons to format SQL while ignoring the commas and rules for writing English text. I personally think you are right. But if most people believed that then there'd be enough support to rewrite SQL with a decent modern syntax. Say allowing training commas before a from.
So the existence of SQL is, in a weird way, evidence that your view is uncommon.
SELECT
a, b, COUNT(*) as count
FROM
table
WHERE
cond1 AND cond2
GROUP BY
a, b
ORDER BY
count DESC - why capitalize KEYWORDS. We're no longer in 1970s. We use colors
- why waste so much space. Why not just put table on the same line with from. With joins this just bloats up
- for complicated conditions they have to be put on their own lines. Do I give each AND a separate line and waste ever more space?- Space is not wasted when it it makes code more readable.
- Yes, and also give the columns in select their own lines. So nice to read. Space well spend!
For heavy SQL codebases found in data analytics, there are better styles.
from ...
where ...
group ...
having ...
select ...
order by ...
limit ...Edit: misread and select was in the middle in that comment
When working in Big Query, it would be so nice to first declare the table, so the online IDE can autocomplete columns.
Can't sympathize with the clause alignment though. And I can't figure out why someone who does leading commas for editability would chose a style that forces you to use different indentation levels for different lines. Oh wait, you wanna make that join a left join? Time to go re-indenting my whole damn query...
It's not even an improvement in readability...who actually reads text like it's a column format? It's not a spreadsheet.
The language is just too lenient with syntax, what is quite on the line for a "human legible" language from the late 70's and earlier 80's, but a really undesirable characteristic in practice. Unfortunately, nobody is doing a "better SQL", just radically different things that often not even support the same DB engines. And those have a real hard time getting popular, so we are stuck with the late 70's speculative innovations.
The GitLab SQL style guide isn't far off either: https://about.gitlab.com/handbook/business-technology/data-t...
Rather than supporting _all_ ways of formatting SQL, the aim of the tool was to fairly flexibly support the most mainstream ones with a view to becoming more opinionated in future to converge on a more unified style in future. Similar to what black has done with python.
select
a,
b,
from ...
without the comma diff when you add one to the end.As far as I understand, this has been quite a long time coming, and is far from trivial due to the diversity of SQL dialect.
My use case would be to have this attached to a dbt project that ensures the dbt SQL files all confirm to a passable degree of consistency when working across a team. Especially as a CICD automated bot action thing on github.
Rule_L031: Avoid table aliases in from clauses and join conditions.
I can't see what makes aliases clarifying in `select` or `where` but not in `join`. Also, inlined subqueries in a join must be given an alias, so there are cases where this rule can't be applied consistently.
sales.amount orders.due_date
vs
s.amount ord.due_date
In the second example I have to flip back and forth between the join statement in order to know where the columns are coming from.
If you have awful table names though like qq123xc then I think aliasing would be appropriate
Moreover, there's nothing wrong with saying `SELECT ... FROM sales sales ...`.
Inlined subqueries are creating entirely new projections so they need descriptive names. If you are doing this you should consider a WITH anyway.
schema.adjective_noun_adjective_noun as anan CREATE OR REPLACE FUNCTION public.setof_test()
RETURNS SETOF text
LANGUAGE sql
STABLE STRICT
AS $function$
select unnest(array['hi', 'test'])
$function$
;[1] https://github.com/sqlfluff/sqlfluff/blob/main/src/sqlfluff/...
Added this here: https://github.com/sqlfluff/sqlfluff/pull/1522
Demonstrating how easy it is to add this sort of thing to the project thanks to how the code is structured! :-)
Obviously this depends on the rules configuration, but just judging that first smell test, it seems very ill thought out.
"= NULL" is as syntactically correct in SQL as "if (x = null)" in C.
If it wasn't, code highlighting or compiling would break, both of which are much much more obvious.
Including autofixing if wanted.
Will be in the next release.
The authors should probably be selling it on that point since it seems to be its strength, it doesn't have many rules along the lines of the static analysis that people look for in linters.
Some people (tech leads, CTOs) care a lot about formatting but I wouldn't make teammates go through a linter for that, it's a rather surface concern.
select a, b, c
from foo
where bar = 'quux'
rather than SELECT
a,
b,
c
FROM
foo
WHERE
bar = 'quux'
is petty and immaterial to what the code communicates.Worse if it's about details within the roughly the same style.
Edit: but if there's a code formatter that can be seamlessly added to the development environment, it makes sense to use it. It's just that if there's no tool support, such things are of little contribution.
Many folks will get sloppy (in syntax and cleanliness) or misunderstand things - which requires the reviewer be able to clearly and quickly see what they are trying to do to catch that - especially as deadlines approach. The more it slips, the more slipping becomes the norm, and the messier and harder to understand everything gets - which makes later work harder as well.
If what you're showing is the standard, I guarantee 25% or more of the requested changes (which already won't meet whatever standard ANYONE sets strictly when first proposed) will be even worse. If that even worse becomes standard, etc, etc.
Part of their job is to set the 'reasonable' ideal, and attempt to enforce it. It won't happen universally, or even necessarily often, but it pushes things more towards maintainability and obviousness, which is opposite of the normal trend in any group of people. The larger the group, the more of a problem it is, and the harder they need to work to do it.
The ability to read complex code when we are in situations where we are not functioning at 100% is vastly under valued when one talks about developers capacity for comprehension.
Sqlfluff seems to ship with 48 "built-in" rules and opinions on spacing and capitalization. If it catches on, I think the larger community will mostly benefit after other companies "doing work" with it release their own collection of rules.
My goal is to use it with a Rockset database, so I’ll see how far I can get with one of the existing dialects, or how hard it is to extend an existing one to make one for Rockset
For example, if you use something like myBatis, you'll probably build the SQL dynamically, which could be stored in a mapper XML file: https://mybatis.org/mybatis-3/dynamic-sql.html
Not only that, but certain frameworks have you embedding SQL inside of the main application code, when you're not using a DSL like HQL: https://www.tutorialspoint.com/hibernate/hibernate_query_lan... and https://www.tutorialspoint.com/hibernate/hibernate_native_sq...
Furthermore, there seems to be this odd separation between "regular SQL" and "procedural SQL" in some DBVSes, such as in Oracle - there you might have to use "DECLARE ... BEGIN ... END;" in certain contexts, or maybe "EXECUTE IMMEDIATE". Then again, Oracle isn't among the supported dialects, which is perfectly understandable, because of both how the DBVS is positioned, as well as because of how large an undertaking supporting it would be: https://docs.sqlfluff.com/en/stable/dialects.html
In short, the only passable tools that i've found for checking SQL are those that are integrated within the IDE, or using a specialized IDE with any plugins for specific technologies, like JetBrains DataGrip (commercial project): https://www.jetbrains.com/datagrip/
But then you run into the issue of code style preferences: some companies have style guides where you have to use reserved words in uppercase with the dev created content in lowercase, like:
SELECT some_column, another_column, yet_another_column AS one_more
FROM some_table
WHERE some_column > SYSDATE
while certain tools (like SQL Developer) are more than happy to use autocomplete which doesn't work well with that: SELECT (start typing in "som") FROM some_table ...
Oracle will autocomplete to: SOME_COLUMN
And then you run into people's personal preferences, for example some format the columns that they want to select like this: SELECT
some_column
, another_column
, yet_another_column
FROM ...
which makes sense when you want to edit single lines, but could have been avoided by the SQL standard allowing dangling commas, like some other languages do, for example: SELECT
some_column,
another_column,
yet_another_column,
FROM ...
but as it currently stands, that's not possible and the other way of formatting code also tends to break linters. And since the actual formatting of SQL doesn't matter as much as it would in Python, we end up with every IDE and other tool having their own preferences.I guess the lesson here is to avoid complexity as much as possible and just settle on whatever works.