5 SQL tips to make your queries prettier and easier to read | by Axel Furlan | Towards Data Science

Well, SQL queries could be thought as usual code. Even though it works, that’s probably not enough and can surely be improved by applying some formatting standards. Prettier code is easy to analyze and easy to maintain. The same principle applies to SQL queries.
The colleague at your company, who has to review your work, will have a bad time trying to figure out what you are trying to do with a badly formatted query.
Using the wrong or no styling rules will result in slower times of peer-reviewing, slower times to get into production, more errors slipping through and a general lack of motivation to review your work. Bad formatting and styling will also have a future impact, when the client or colleague asks you to change something in the query you did months ago. That huge query you completely forgot what was it all about.
Almost all weird syntax errors that my colleagues and I had were primarily due to bad formatting, because it was hard to spot a wrongly placed comma or a missing parenthesis — those are the worst.
Let’s start!
It is ok to have different casings for different parts of your query, but be consistent. Take a look at this:
SELECT firstName, count(*) from Users WHERE last_name = ‘smith’ Group By firstName
This query is absolutely nasty 😬. If I were the parser reading through this, I’d definitely throw that query some type of syntax error just for it to be revised.
Let’s mark a couple of bad things here:
Some SQL keywords are in UPPERCASE. Some others are in lowercase. The GROUP BY is in Title Case. An optimal formatting rule for keywords is using the same casing across all SQL keywords. Both lowercase and UPPERCASE options are the most used ones.It is not easily distinguishable whether the lowercase keywords are actually keywords or columns since the casing is mixed. Besides, it is also annoying to read.The first column in the SELECT is in camelCase, the one used in the WHERE clause is in snake_case and the table name is in PascalCase. If you encounter these kind of inconsistences across your tables, be sure to ring the alarm and decide with your team which casing you should stick to.
Some SQL keywords are in UPPERCASE. Some others are in lowercase. The GROUP BY is in Title Case. An optimal formatting rule for keywords is using the same casing across all SQL keywords. Both lowercase and UPPERCASE options are the most used ones.
It is not easily distinguishable whether the lowercase keywords are actually keywords or columns since the casing is mixed. Besides, it is also annoying to read.
The first column in the SELECT is in camelCase, the one used in the WHERE clause is in snake_case and the table name is in PascalCase. If you encounter these kind of inconsistences across your tables, be sure to ring the alarm and decide with your team which casing you should stick to.
After some cleaning, the query should look like this:
SELECT first_name, COUNT(*) FROM users WHERE last_name = ‘smith’ GROUP BY first_name
Try to read this query and distinguish each section with a quick glance:
SELECT g.id, COUNT(u.id) FROM users u JOIN groups g on u.group_id = g.id WHERE u.name = 'John' GROUP BY g.id ORDER BY COUNT(u.id) desc
Now, try the same exercise with the following one:
SELECT g.id, COUNT(u.id)FROM users u JOIN groups g on u.group_id = g.idWHERE u.name = 'John'GROUP BY g.idORDER BY COUNT(u.id) desc
Can you see how much easier it is to distinguish each part?
This may be a little change on this query but imagine having to deal with those that have subqueries, multiple joins and maybe even window functions. It is not the same, isn’t it?
Let’s try to add another level of indentation to see how it gets easier:
SELECT    g.id  , COUNT(u.id)FROM users u    JOIN groups g on u.group_id = g.idWHERE u.name = ‘John’GROUP BY    g.idORDER BY    COUNT(u.id) desc
Pro tip: I started using commas before each field in the SELECT clause. Instead of having a trailing comma after each line, I make sure that every line, starting from the second column, starts with a comma. In my opinion, it is easier to read and you don’t have that problem of leaving a comma before the FROM clause giving you a sometimes hard to understand syntax error, depending on your RDBMS.
There’s probably a bit of preference whether you use 2 spaces or 4 for different levels of your query, but you cannot argue it won’t look much cleaner than just one big line of SQL. Or worse: a big chunk of SQL on the same indentation level.
Trust me, your coworkers will appreciate it. 😄
Again, this may be a preference and feel free to take it or not. But throughout my career, I encountered many beginner data analysts that didn’t even know this existed.
Instead of:
SELECT    first_name    , last_name    , COUNT(*)FROM usersGROUP BY    first_name    , last_nameORDER BY    COUNT(*) desc
You can do:
SELECT    first_name    , last_name    , COUNT(*)FROM usersGROUP BY 1, 2ORDER BY 3 desc
This comes with a bunch of simple benefits:
You save lines: Grouping by a lot of fields will not only add more lines in the SELECT clause, but also in your GROUP BY and ORDER BY clauses, maybe even doubling the amount of lines in your query.
Maintainability: If you want to change the columns to group by, just do it in the select clause, no need to remember to do it as well in the other clauses.
It’s faster: If you have the good habit of putting your grouping fields first, the only thing you need to do is GROUP BY 1, 2, 3, ..., n with n being the amount of grouping columns.
Compatible: If you use a tool like dbt, you can even use Jinja to call {{group_by(n)}} and it will translate to the appropriate group by clause.
The so-called CTEs are tools provided to simplify complex querying. They could be defined as temporary views, since they only live during the execution of the whole query. CTEs give you the ability to create subqueries that will be used for the final thing.
Let’s look at a simple example:
WITH employee_by_title_count AS (    SELECT        t.name as job_title        , COUNT(e.id) as amount_of_employees    FROM employees e        JOIN job_titles t on e.job_title_id = t.id    GROUP BY 1),salaries_by_title AS (     SELECT         name as job_title         , salary     FROM job_titles)SELECT *FROM employee_by_title_count e    JOIN salaries_by_title s ON s.job_title = e.job_title
Here you can see that we use both employee_by_title and salaries_by_title in our bottom query to produce the final result. This is more readable and maintainable than doing the subquery in the SELECT clause or directly into the FROM clause. Specially if you are going to use many, it is a lot easier to create simple CTEs than a big chunk of FROM clause with different levels of queries inside of it.
You better be careful though: make sure that you are not reducing performance dramatically by doing things more complex than they should be. To check query performance, you can use EXPLAIN ANALYZE if you’re using PostgreSQL.
A proper title for each column is crucial. That is the first thing someone sees in a spreadsheet. “What columns do I have?” Imagine if that person had a csv with 3 columns named id , 4 named count and others named avg , min and such. He would probably gonna go nuts!
Let’s look at the following query:
SELECT    u.id    , u.name    , t.id    , t.name    , (SELECT COUNT(*) FROM job_titles where name = t.name)FROM users u    JOIN job_title t on u.job_title_id = t.id
The result of this query may be the following:
id, name, id, name, count1, John Wick, 4, hitman, 5
You can probably tell that John Wick is not a job title, so the second column certainly must be the user name. That can also be true with hitman, you can surely tell that’s a job title. But what is count ? 😅 No one could guess that.
Now let’s look at this:
SELECT    u.id as user_id    , u.name as user_name    , t.id as job_title_id    , t.name as job_title_name    , (SELECT COUNT(*) FROM job_titles where name = t.name) as count_users_with_jobFROM users u    JOIN job_title t on u.job_title_id = t.id
This query will produce much more readable and understandable columns. The person that receives this report can spot valuable information at a glance and will to be a lot happier than the one that received the previous result.
I aimed to make your life easier with this article. Whether you are a developer, data analyst, data scientist or just someone that does SQL at your company, this should come in handy and reduce a lot of headaches throughout your work.
Remember: there’s no single best standard or layout for SQL formatting, but there certainly should be one that you like best. The challenge that comes now is finding that specific one and ensure that you are consistent with it. Discuss with your colleagues what formatting rules they like and reach consensus with the team to ensure you all agree on using the same rules across all the company’s queries.
I hope you found this useful. Until next time! 😄