← back to the formatter

The Vitti SQL indentation style

The conventions the formatter applies. Default indent is tabs (width 4); switch to spaces for editors like Databricks where the tab width differs. Programmatic use: the API ↗.

1.  Casing

Reserved keywords, built-in functions and data types are lowercase (select, left join, row_number, isnull, decimal(20,2)). Identifiers — schema/table/column names — keep their original case.

2.  The "river"

Every clause keyword sits in a left column; its operand starts at a fixed tab stop (column 12), forming a vertical river. Keyword and first operand share a line.

select      first_expression                alias
            ,second_expression              alias
from        schema.table  t
where       1=1
and          t.flag = 1

3.  Leading commas

List items break before the comma, aligned in the river column.

4.  Aligned aliases

In a select list, aliases line up in a second column (no as). Outlier-long expressions keep a single-tab gap instead of dragging everyone right.

5.  where 1=1

Every where opens with 1=1; each real predicate is its own and/or line — trivially commentable and reorderable. Same for multi-condition on.

6.  Blank lines between blocks

One blank line separates the select list, from, each join, where, group by… for an airy, scannable layout.

7.  insert into

insert into base.target (
    col_a
    ,col_b)
select      src.col_a                       col_a
            ,src.col_b                       col_b
from        ...

8.  update … set … from

Assignments use leading commas with the = signs aligned into their own column; from + joins + where 1=1 follow like a select.

9.  case

,(case
    when x is null              then -1
    else 0
end)                                        flag

10.  Window functions

Short windows stay inline; long ones explode, giving partition by/order by their own mini-river. Named windows in a window clause explode the same way.

,row_number() over (
    partition by    pa.customer_nrc
                    ,pa.access_point_id
    order by        pa.promo_start_date asc)    sorting_asc

11.  CTEs

with cte_count as (
    select      customer_id
                ,max(temp_order)            max_order
    from        base.history
    group by    customer_id)

update      base
set         ...

12.  Banner comments

Sections separated by an indented star-banner block comment.

13.  Inline spacing

No space after commas inside argument lists (isnull(x,0), in (5,6)); spaces around comparison/arithmetic operators; . binds tight.

14.  merge

merge into / using are river lines; the on condition reads like a join; each when … then update / insert / delete is its own block. A subquery in using (…) is formatted recursively (see 17).

15.  DDL — create table / alter table

Inline column lists get leading commas with the type aligned into a column; data types are lowercased.

create or replace table z.t
            (reference_month    int
            ,plan_id            decimal(20,0) not null
            ,plan_name          varchar(100));

16.  begin … end blocks

Compound blocks are formatted, not passed through — the statements inside are indented one level (including a nested declare … handler … begin … end). begin transaction is left alone.

17.  Subqueries (recursive)

Derived tables in from/join, merge using (…), and nested subqueries at any depth format as a block: ( and ) on their own lines, inner query one indent deeper, alias after ).

from        (
                select      a.id
                            ,sum(a.v)   tot
                from        base.a a
                where       1=1
                and         a.flag = 1
            )   x

18.  Multiple statements

A script with several statements is split and each is formatted — separated by ; or just by a blank line (guarded so union, insert…select, CTEs and merge clauses are never cut apart).

Scope: query DML (select / insert / update / delete / merge), DDL (create / alter table), CTEs, case, window functions, subqueries and begin…end blocks. Other procedural wrappers (create/alter procedure, exec, use, go) are passed through untouched.