SQL formatting standards

SqlSql ServerFormattingStandardsCoding Style

Sql Problem Overview


In my last job, we worked on a very database-heavy application, and I developed some formatting standards so that we would all write SQL with a common layout. We also developed coding standards, but these are more platform-specific so I'll not go into them here.

I'm interested to know what other people use for SQL formatting standards. Unlike most other coding environments, I haven't found much of a consensus online for them.

To cover the main query types:

select
	ST.ColumnName1,
	JT.ColumnName2,
	SJT.ColumnName3
from 
    SourceTable ST
inner join JoinTable JT
	on JT.SourceTableID = ST.SourceTableID
inner join SecondJoinTable SJT
	on ST.SourceTableID = SJT.SourceTableID
	and JT.Column3 = SJT.Column4
where
	ST.SourceTableID = X
	and JT.ColumnName3 = Y

There was some disagreement about line feeds after select, from and where. The intention on the select line is to allow other operators such as "top X" without altering the layout. Following on from that, simply keeping a consistent line feed after the key query elements seemed to result in a good level of readability.

Dropping the linefeed after the from and where would be an understandable revision. However, in queries such as the update below, we see that the line feed after the where gives us good column alignment. Similarly, a linefeed after group by or order by keeps our column layouts clear and easy to read.

update
	TargetTable
set
	ColumnName1 = @value,
	ColumnName2 = @value2
where
	Condition1 = @test

Finally, an insert:

insert into TargetTable (
	ColumnName1,
	ColumnName2,
	ColumnName3
) values (
	@value1,
	@value2,
	@value3
)

For the most part, these don't deviate that far from the way MS SQL Server Managements Studio / query analyser write out SQL, however they do differ.

I look forward to seeing whether there is any consensus in the Stack Overflow community on this topic. I'm constantly amazed how many developers can follow standard formatting for other languages and suddenly go so random when hitting SQL.

Sql Solutions


Solution 1 - Sql

Late answer, but hopefully useful.

My experience working as part of the larger development team is that you can go ahead and define any standards you like, but the problem is actually enforcing these or making it very easy for developers to implement.

As developers we sometimes create something that works and then say “I’ll format it later”, but that later never comes.

Initially, we used SQL Prompt (it was great) for this, but then switched to ApexSQL Refactor, because it’s a free tool.

Solution 2 - Sql

I'm late to the party, but I'll just add my preferred formatting style, which I must've learned from books and manuals: it's compact. Here's the sample SELECT statement:

SELECT  st.column_name_1, jt.column_name_2,
        sjt.column_name_3
FROM    source_table AS st
        INNER JOIN join_table AS jt USING (source_table_id)
        INNER JOIN second_join_table AS sjt ON st.source_table_id = sjt.source_table_id
                AND jt.column_3 = sjt.column_4
WHERE   st.source_table_id = X
AND     jt.column_name_3 = Y

In short: 8-space indentation, keywords in caps (although SO colours them better when in lowercase), no camelcase (pointless on Oracle), and line wraps when needed.

The UPDATE:

UPDATE  target_table
SET     column_name_1 = @value,
        column_name_2 = @value2
WHERE   condition_1 = @test

And the INSERT:

INSERT  INTO target_table (column_name_1, column_name_2,
                column_name_3)
VALUES  (@value1, @value2, @value3)

Now, let me be the first to admit that this style has it's problems. The 8-space indent means that ORDER BY and GROUP BY either misalign the indent, or split the word BY off by itself. It would also be more natural to indent the entire predicate of the WHERE clause, but I usually align following AND and OR operators at the left margin. Indenting after wrapped INNER JOIN lines is also somewhat arbitrary.

But for whatever reason, I still find it easier to read than the alternatives.

I'll finish with one of my more complex creations of late using this formatting style. Pretty much everything you'd encounter in a SELECT statement shows up in this one. (It's also been altered to disguise its origins, and I may have introduced errors in so doing.)

SELECT  term, student_id,
        CASE
            WHEN ((ft_credits > 0 AND credits >= ft_credits) OR (ft_hours_per_week > 3 AND hours_per_week >= ft_hours_per_week)) THEN 'F'
            ELSE 'P'
        END AS status
FROM    (
        SELECT  term, student_id,
                pm.credits AS ft_credits, pm.hours AS ft_hours_per_week,
                SUM(credits) AS credits, SUM(hours_per_week) AS hours_per_week
        FROM    (
                SELECT  e.term, e.student_id, NVL(o.credits, 0) credits,
                        CASE
                            WHEN NVL(o.weeks, 0) > 5 THEN (NVL(o.lect_hours, 0) + NVL(o.lab_hours, 0) + NVL(o.ext_hours, 0)) / NVL(o.weeks, 0)
                            ELSE 0
                        END AS hours_per_week
                FROM    enrollment AS e
                        INNER JOIN offering AS o USING (term, offering_id)
                        INNER JOIN program_enrollment AS pe ON e.student_id = pe.student_id AND e.term = pe.term AND e.offering_id = pe.offering_id
                WHERE   e.registration_code NOT IN ('A7', 'D0', 'WL')
                )
                INNER JOIN student_history AS sh USING (student_id)
                INNER JOIN program_major AS pm ON sh.major_code_1 = pm._major_code AND sh.division_code_1 = pm.division_code
        WHERE   sh.eff_term = (
                        SELECT  MAX(eff_term)
                        FROM    student_history AS shi
                        WHERE   sh.student_id = shi.student_id
                        AND     shi.eff_term <= term)
        GROUP   BY term, student_id, pm.credits, pm.hours
        )
ORDER   BY term, student_id

This abomination calculates whether a student is full-time or part-time in a given term. Regardless of the style, this one's hard to read.

Solution 3 - Sql

I am of the opinion that so long as you can read the source code easily, the formatting is secondary. So long as this objective is achieved, there are a number of good layout styles that can be adopted.

The only other aspect that is important to me is that whatever coding layout/style you choose to adopt in your shop, ensure that it is consistently used by all coders.

Just for your reference, here is how I would present the example you provided, just my layout preference. Of particular note, the ON clause is on the same line as the join, only the primary join condition is listed in the join (i.e. the key match) and other conditions are moved to the where clause.

select
    ST.ColumnName1,
    JT.ColumnName2,
    SJT.ColumnName3
from 
    SourceTable ST
inner join JoinTable JT on 
    JT.SourceTableID = ST.SourceTableID
inner join SecondJoinTable SJT on 
    ST.SourceTableID = SJT.SourceTableID
where
        ST.SourceTableID = X
    and JT.ColumnName3 = Y
    and JT.Column3 = SJT.Column4

One tip, get yourself a copy of SQL Prompt from Red Gate. You can customise the tool to use your desired layout preferences, and then the coders in your shop can all use it to ensure the same coding standards are being adopted by everyone.

Solution 4 - Sql

SELECT
    a.col1 				    AS [Column1]
    ,b.col2 				AS [Column2]
    ,c.col1 				AS [Column3]
FROM
    Table1 a
	INNER JOIN Table2 b 	ON b.Id = a.bId
	INNER JOIN Table3 c 	ON c.Id = a.cId
WHERE
	a.col     = X
	AND b.col = Y

Uses much more lines than a lot of the examples here, but I feel it's a lot easier to understand, enables quick removal of columns/clauses/tables. It helps to take advantage of a vertically-oriented monitor.

Solution 5 - Sql

Late, but I'll throw my hat in the ring. It takes a bit longer to write, but I find patterns emerge with the vertical alignment that make it very readable once you're used to it.

SELECT ST.ColumnName1,
       JT.ColumnName2,
       SJT.ColumnName3,
       CASE WHEN condition1 = True 
             AND condition2 = True Then DoSomething
            Else DoSomethingElse
        END ColumnName4
  FROM SourceTable AS ST
 INNER
  JOIN JoinTable AS JT
    ON JT.SourceTableID = ST.SourceTableID
 INNER
  JOIN SecondJoinTable AS SJT
    ON ST.SourceTableID = SJT.SourceTableID
   AND JT.Column3 = SJT.Column4
  LEFT
  JOIN (SELECT Column5
          FROM Table4
       QUALIFY row_number() OVER
                 ( PARTITION BY pField1,
                                pField2
                       ORDER BY oField1
                 ) = 1
       ) AS subQry
    ON SJT.Column5 = subQry.Column5
 WHERE ST.SourceTableID = X
   AND JT.ColumnName3 = Y

Solution 6 - Sql

Nice. As a Python programmer, here are my preferences:

Newlines after select, from and where only when it is needed for readability.

When code can be more compact and equally readable, I usually prefer the more compact form. Being able to fit more code in one screenful improves productivity.

select ST.ColumnName1, JT.ColumnName2, SJT.ColumnName3
from SourceTable ST
inner join JoinTable JT
    on JT.SourceTableID = ST.SourceTableID
inner join SecondJoinTable SJT
    on ST.SourceTableID = SJT.SourceTableID
    and JT.Column3 = SJT.Column4
where ST.SourceTableID = X and JT.ColumnName3 = Y

Ultimately, this will be a judgment call that will be made during code review.

For insert, I would place the parenthesis differently:

insert into TargetTable (
    ColumnName1,
    ColumnName2,
    ColumnName3)
values (
    @value1,
    @value2,
    @value3)

The reasoning for this formatting is that if SQL used indentation for block structure (like Python), the parenthesis would not be needed. So, if indentation is used anyway, then parenthesis should have the minimum effect on the layout. This is achieved by placing them at the end of the lines.

Solution 7 - Sql

I am working on writing an open-source SQL Formatter (SQL-Server-only at this stage) in C#, so I put the above queries through it.

It employs a similar strategy to the OP, namely that each 'section' has child elements indented beneath it. Where required, I add white space between sections to aid clarity – these wouldn't be added when there are no joins or minimal where conditions.

Result:

SELECT
    ST.ColumnName1,
    JT.ColumnName2,
    SJT.ColumnName3

FROM SourceTable ST

INNER JOIN JoinTable JT
        ON JT.SourceTableID = ST.SourceTableID

INNER JOIN SecondJoinTable SJT
        ON ST.SourceTableID = SJT.SourceTableID
       AND ST.SourceTable2ID = SJT.SourceTable2ID

WHERE ST.SourceTableID = X
  AND JT.ColumnName3 = Y
  AND JT.Column3 = SJT.Column4

ORDER BY
    ST.ColumnName1

Solution 8 - Sql

I would suggest the following style, based on the John's suggestion:

/*
<Query title>
<Describe the overall intent of the query>
<Development notes, or things to consider when using/interpreting the query>
*/
select
	ST.ColumnName1,
	JT.ColumnName2,
	SJT.ColumnName3
from 

	-- <Comment why this table is used, and why it's first in the list of joins>
	SourceTable ST
		
	-- <Comment why this join is made, and why it's an inner join>
	inner join JoinTable JT
		on ST.SourceTableID = JT.SourceTableID
		
	-- <Comment why this join is made, and why it's an left join>
	left join SecondJoinTable SJT
		on	ST.SourceTableID = SJT.SourceTableID
		and JT.Column3 = SJT.Column4
	
where
	
	-- comment why this filter is applied
	ST.SourceTableID = X
		
	-- comment why this filter is applied
	and JT.ColumnName3 = (
			select 
				somecolumn
			from 
				sometable
		)
;

Advantages:

  • Comments are an essential part of making code readable and detecting mistakes.
  • Adding -all- "on"-filters to the join avoids mistakes when changing from inner to left join.
  • Placing the semicolon on a newline allows for easy adding/commenting of where clauses.

Solution 9 - Sql

I tend to use a layout similar to yours, although I even go a few steps further, e.g.:

select
        ST.ColumnName1
    ,   JT.ColumnName2
    ,   SJT.ColumnName3
from
                SourceTable     ST
    
    inner join  JoinTable       JT
        on  JT.SourceTableID    =   ST.SourceTableID
    
    inner join  SecondJoinTable SJT
        on  ST.SourceTableID    =   SJT.SourceTableID
        
where
        ST.SourceTableID    =   X
    and JT.ColumnName3      =   Y
    and JT.Column3          =   SJT.Column4

Perhaps it looks a little over the top at first, but IMHO the use of tabulation in this way gives the cleanest, most systematic layout given the declarative nature of SQL.

You'll probably end up with all sorts of answers here. In the end, it's down to personal or team-agreed preferences.

Solution 10 - Sql

I use a format similar to yours except that I put the ON keyword on the same line as the join and I put AND and OR operators at the end of lines so that all of my join/selection criteria line up nicely.

While my style is similar to John Sansom's, I disagree about putting join criteria in the WHERE clause. I think that it should be with the joined table so that it's organized and easy to find.

I also tend to put parentheses on new lines, aligned with the line above it and then indenting on the next line, although for short statements, I may just keep the parentheses on the original line. For example:

SELECT
     my_column
FROM
     My_Table
WHERE
     my_id IN
     (
          SELECT
               my_id
          FROM
               Some_Other_Table
          WHERE
               some_other_column IN (1, 4, 7)
     )

For CASE statements, I give a new line and indentation for each WHEN and ELSE, and I align the END back to the CASE:

CASE
     WHEN my_column = 1 THEN 'one'
     WHEN my_column = 2 THEN 'two'
     WHEN my_column = 3 THEN 'three'
     WHEN my_column = 4 THEN 'four'
     ELSE 'who knows'
END

Solution 11 - Sql

The number of differing opinions is scary. This is what my organization uses:

 SELECT ST.ColumnName1,
        JT.ColumnName2,
        SJT.ColumnName3
   FROM SourceTable ST
  INNER JOIN JoinTable JT ON JT.SourceTableID = ST.SourceTableID
  INNER JOIN SecondJoinTable SJT ON ST.SourceTableID = SJT.SourceTableID 
        AND JT.Column3 = SJT.Column4
  WHERE ST.SourceTableID = X
    AND JT.ColumnName3 = Y

Maintaining the 8-character indent is key to readability IMHO.

Solution 12 - Sql

Nobody's done common table expressions (CTEs) yet. Below incorporates it along with some other styles I use:

declare @tableVariable table (
    colA1 int,
    colA2 int,
    colB1 int,
    colB2 nvarchar(255),
    colB3 nvarchar(255),
    colB4 int,
    colB5 bit,
    computed int
);

with

    getSomeData as (

        select        st.colA1, sot.colA2
        from          someTable st
        inner join    someOtherTable sot on st.key = sot.key

    ),

    getSomeOtherData as (

        select        colB1, 
                      colB2, 
                      colB3,
                      colB4,
                      colB5,
                      computed =    case 
                                    when colB5 = 1 then 'here'
                                    when colB5 = 2 then 'there'
                                    end
        from          aThirdTable tt
        inner hash 
         join         aFourthTable ft
                      on tt.key1 = ft.key2
                      and tt.key2 = ft.key2
                      and tt.key3 = ft.key3

    )

    insert      @tableVariable (
                    colA1, colA2, colA2, 
                    colB1, colB2, colB3, colB4, colB5, 
                    computed 
                )
    select      colA1, colA2, 
                colB1, colB2, colB3, colB4, colB5, 
                computed 
    from        getSomeData data1
    join        getSomeOtherData data2

A few points on the CTE format:

  • In my CTEs "with" is on a seperate line, and everything else in the cte is indented.
  • My CTE names are long and descriptive. CTE's can get complex and descriptive names are very helpful.
  • For some reason, I find myself preferring verbs for CTE names. Makes it seem more lively.
  • Similar style with the parentheses as Javascript does with its braces. It's also how I do the braces in C#.

This simulates:

func getSomeData() {

    select        st.colA1, sot.colA2
    from          someTable st
    inner join    someOtherTable sot on st.key = sot.key

}

A few points besides the CTE format:

  • Two tabs after "select" and other keywords. That leaves enough room for "inner join", "group by", etc. You can see one example above where that's not true. But "inner hash join" SHOULD look ugly. Nevertheless, on this point I'm probably going to experiment with some of the styles above in the future.
  • Keywords are lowercase. Their colorization by the IDE and their special indentation status highlight them enough. I reserve uppercase for other things I want to emphasize based on local (business) logic.
  • If there are few columns, I put them on one row (getSomeData). If there are a few more, I verticalize them (getSomeOtherData). If there is too much verticalization in one unit, I horizontalize some columns into the same line grouped by locally defined logic (the final insert-select segment). For instance, I would put school-level information on one line, student-level on another, etc.
  • Especially when verticalizing, I prefer sql server's "varname = colname + something syntax" to "colname + something as varname".
  • Double the last point if I'm dealing with a case statement.
  • If a certain logic lends itself to a 'matrix' style, I will deal with the typing consequences. That's sort of what's going on with the case statement, where the 'whens' and 'then's are aligned.

I find that I am more settled on my CTE style than other areas. Haven't experimented with the styles more similar to that posed in the question. Probably will do someday and see how I like it. I'm probably cursed to be in an environment where it's a choice, though it's a fun curse to have.

Solution 13 - Sql

If I am making changes to already written T-SQL, then I follow the already used convention (if there is one).

If I am writing from scratch or there is no convention, then I tend to follow your convention given in the question, except I prefer to use capital letters for keywords (just a personal preference for readability).

I think with SQL formatting as with other code format conventions, the important point is to have a convention, not what that convention is (within the realms of common sense of course!)

Solution 14 - Sql

Yeah I can see the value of laying out your sql in some rigourously defined way, but surely the naming convention and your intent are far more important. Like 10 times more important.

Based on that my pet hates are tables prefixed by tbl, and stored procedures prefixed by sp - we know they're tables and SPs. Naming of DB objects is far more important than how many spaces there are

Just my $0.02 worths

Solution 15 - Sql

I realise I am very late to this debate, but I would like to give my thoughts. I am definitely in favour of commas at the start of the line. Like you say Adam Ralph, it's easier to comment out a field and I also find it is more difficult to miss out a comma accidently when they are at the beginning, whilst this doesn't sound like a major issue. I have spent hours in the past trying to track down accidental syntax errors in lengthy T-SQL procedures, where I have accidently missed out a comma at the end of the line (I'm sure some of you have probably done this as well). I'm also in favour of aliasing as much as possible.

Overall, though, I realise it's all down to personal preference, what works for some doesn't for others. As long as you can read the code easily and each developer shows some consistency in their style throughout, I think that's most important.

Solution 16 - Sql

I like:

SELECT ST.ColumnName1, JT.ColumnName2, SJT.ColumnName3 --leave all selected columns on the same line
FROM 
    SourceTable ST
INNER JOIN JoinTable JT ON JT.SourceTableID = ST.SourceTableID
INNER JOIN SecondJoinTable SJT --only splitting lines when more than 1 condition
    ON ST.SourceTableID = SJT.SourceTableID
    AND JT.Column3 = SJT.Column4
WHERE
    ST.SourceTableID = X
    and JT.ColumnName3 = Y

to get more code in a smaller viewing area. I also beleive that keywords should be in capitals

Solution 17 - Sql

I agree whole heartily with your effort to standardize SQL formatting within your project and in general.

I also very much agree with your formatting choices. I have come up with nearly the same one, save I also indent the 'join' statements, and with them the 'on' statements one more indent.

Very much like the fact that you go for lower case on keywords - Who want's those SHOUTED OUT at you. I also prefer to lower case table aliases - makes for better readability

Very much like the fact that you use small indentation (4). I go with (3).

I nix the terms 'inner' and 'outer' as then are unnecessary.

Here is how would have formatted your select statement:

select
   st.ColumnName1,
   jt.ColumnName2,
   sjt.ColumnName3
from 
   SourceTable st
   join JoinTable jt on jt.SourceTableID = st.SourceTableID
   join SecondJoinTable sjt on
      st.SourceTableID = sjt.SourceTableID and
      jt.Column3 = sjt.Column4
where
   st.SourceTableID = X
   and jt.ColumnName3 = Y
;

Thanks for discussing this.

Solution 18 - Sql

There are many good points in this thread. The one standard that I have been attempting to convince people to use is placing the comma on the same line before each column. Like so:

Select column1
   ,column2
   ,column3
   ,column4
   ,Column5 ...ect

Opposed to:

Select column1,
   column2,
   column3, ect...

The reason I prefer this practice is because, if necessary, you can comment out a line and there wont be a comma issue when you run it on account of the corresponding comma being commented out as well. I know that I saw another user in the thread that had done this as well but did not really point it out. Not a huge revelation to bring to the conversation but my two cents. Thanks

Solution 19 - Sql

This is the format that I use. Please comment if it can be make better.

CREATE PROCEDURE [dbo].[USP_GetAllPostBookmarksByUserId]
	@id INT,
	@startIndex INT,
	@endIndex INT
AS
BEGIN
	
	SET NOCOUNT ON

	SELECT		*
	FROM
			(	SELECT		ROW_NUMBER() OVER ( ORDER BY P.created_date ) AS row_num, P.post_id, P.title, P.points, p.estimated_read_time, P.view_count, COUNT(1) AS "total_attempts" -- todo
				FROM		[dbo].[BOOKMARKED] B
				INNER JOIN	[dbo].[POST] P
				ON			B.entity_id = P.post_id
				INNER JOIN	[dbo].[ATTEMPTED] A
				ON			A.entity_id = P.post_id
				WHERE		B.user_id = 1 AND P.is_active = 1
				GROUP BY	P.post_id, P.title, P.points, p.estimated_read_time, P.view_count
			)	AS PaginatedResult
	WHERE		row_num >= @startIndex
	AND			row_num < @endIndex
	ORDER BY	row_num
	
END

Solution 20 - Sql

My answer will be similar to the accepted answer by John Sansom answered Feb 6 '09 at 11:05. However, I will demonstrate some formatting options using SQLInForm plugin in NOTEPAD++, as opposed to his answer with SQL Prompt from Red Gate.

The SQLInForm plugin has 5 different profiles you can setup. Within the profile there are lots of settings available in both the FREE and PAID versions. An exhaustive list is below and you can see their plugin-help-general-options page online.

Instead of rambling about my preferences I considered it would be useful to present the SQLInForm options available. Some of my preferences are also noted below. At the end of my post is the formatted SQL Code used in the original post (original VS format1 VS format2).

Reading through other answers here-- I seem to be in the minority on a couple things. I like leading commas (Short Video Here)-- IMO, It is much easier to read when a new field is being selected. And also I like my Column1 with linebreak and not next to the SELECT.


Here is an overview with some of my preferences notes, considering a SELECT Statement. I would add screenshots of all 13 sections; But that is a lot of screenshots and I would just encourage you to the the free edition-- take some screenshots, and test the format controls. I will be testing out Pro edition soon; But based on the options it looks like it will be really helpful and for only $20.

SQLInForm Notepadd++: Options & Preferences

> 1. General (free) > >> DB: Any SQL, DB2/UDB, Oracle, MSAccess, SQL Server, Sybase, MYSQL, >> PostgreSQL, Informix, Teradata, Netezza SQL > >> [Smart Indent]= FALSE > > 2. Colors (free) > > 3. Keywords (PRO) > >> [Upper/LowerCase]> Keywords > > 4. Linebreaks> Lists (free) > >> [Before Comma]=TRUE 5 > >> [Move comma 2 cols to the left]= FALSE > > 5. Linebreaks>Select (PRO) > >> [JOIN> After JOIN]= FALSE > >> [JOIN> Before ON]= FALSE > >> (no change)--> [JOIN> Indent JOIN]; [JOIN> After ON] > > 6. Linebreaks> Ins/Upd/Del (PRO) > > 7. Linebreaks> Conditions (PRO) > >> CASE Statement--> [WHEN], [THEN], [ELSE] … certainly want to play >> with these settings and pick a good one > > 8. Alignment (PRO) > >> (no change)--> [JOIN> Indent JOIN]; [JOIN> After ON] > > 9. White Spaces (PRO) > >> (change?) Blank Lines [Remove All]=TRUE; [Keep All]; [Keep One] > > 10. Comments (PRO) > >> (change?) Line & Block--> [Linebreak Before/ After Block >> Comments]=TRUE; [Change Line Comments into Block]; [Block into Line] > > 11. Stored Proc (PRO) > > 12. Advanced (PRO) > >> (Could be useful) Extract SQL from Program Code--> [ExtractSQL] > > 13. License


SQL Code

The original query format.

select
    ST.ColumnName1,
    JT.ColumnName2,
    SJT.ColumnName3
from 
    SourceTable ST
inner join JoinTable JT
    on JT.SourceTableID = ST.SourceTableID
inner join SecondJoinTable SJT
    on ST.SourceTableID = SJT.SourceTableID
    and JT.Column3 = SJT.Column4
where
    ST.SourceTableID = X
    and JT.ColumnName3 = Y

CONVERSION PREFERRED FORMAT (option #1: JOIN no linebreak)

SELECT
    ST.ColumnName1
    , JT.ColumnName2
    , SJT.ColumnName3
FROM
    SourceTable ST
    inner join JoinTable JT 
		on JT.SourceTableID = ST.SourceTableID
    inner join SecondJoinTable SJT
		on ST.SourceTableID = SJT.SourceTableID
		and JT.Column3      = SJT.Column4
WHERE
    ST.SourceTableID   = X
    and JT.ColumnName3 = Y

CONVERSION PREFERRED FORMAT (option #2: JOIN with linebreak)

SELECT	
    ST.ColumnName1
    , JT.ColumnName2
    , SJT.ColumnName3
FROM
    SourceTable ST
    inner join
		JoinTable JT
		on JT.SourceTableID = ST.SourceTableID
    inner join
        SecondJoinTable SJT
		on ST.SourceTableID = SJT.SourceTableID
		and JT.Column3      = SJT.Column4
WHERE
    ST.SourceTableID   = X
    and JT.ColumnName3 = Y

Hope this helps.

Solution 21 - Sql

Better late than never. I use a different style and adopted it from a very good SQL developer I used to work with. I right-align keywords and I don't use UPPERCASE letters for the ease of typing. The keywords will be highlighted by the editor and I don't see a need for them to be in the UPPERCASE unless you do lots of editing in text editors that does not support keyword-highlighting features. I don't try to make it compact, but rather more readable and vertically-aligned as much as possible. Here is an example of a select taken from @BenLaan answer written in my format:

select st.ColumnName1
       , jt.ColumnName2
       , sjt.ColumnName3
  from SourceTable st
         inner join
       JoinTable jt
         on jt.SourceTableID = st.SourceTableID
         inner join
       SecondJoinTable sjt
         on st.SourceTableID = sjt.SourceTableID
         and st.SourceTable2ID = sjt.SourceTable2ID
 where st.SourceTableID = X
       and jt.ColumnName3 = Y
       and jt.Column3 = sjt.Column4
 order by st.ColumnName1

Trying to conform all the team to follow the same formatting pattern is the hardest thing. I would follow any format, if everyone else followed the same way, but it has never been the same story.

UPDATE: Rewriting one of the complex queries mentioned in earlier posts:

select
       term
       , student_id
       , case
           when((ft_credits > 0 and credits >= ft_credits) or (ft_hours_per_week > 3 and hours_per_week >= ft_hours_per_week))
             then 'F'
           else 'P'
         end as status
  from (select term
               , student_id
               , pm.credits AS ft_credits
               , pm.hours AS ft_hours_per_week
               , SUM(credits) AS credits
               , SUM(hours_per_week) AS hours_per_week
          from (select e.term
                       , e.student_id
                       , nvl(o.credits, 0) credits
                       , case
                           when nvl(o.weeks, 0) > 5 
                             then (nvl(o.lect_hours, 0) + nvl(o.lab_hours, 0) + nvl(o.ext_hours, 0)) / nvl(o.weeks, 0)
                           else 0
                        end as hours_per_week
                  from enrollment as e
                         inner join 
                       offering as o using (term, offering_id)
                         inner join
                       program_enrollment as pe 
                         on e.student_id = pe.student_id 
                         and e.term = pe.term 
                         and e.offering_id = pe.offering_id
                 where e.registration_code not in ('A7', 'D0', 'WL')
                )
                  inner join 
                student_history as sh using (student_id)
                  inner join 
                program_major as pm 
                  on sh.major_code_1 = pm._major_code and sh.division_code_1 = pm.division_code
         where sh.eff_term = (select max(eff_term)
                                from student_history as shi
                               where sh.student_id = shi.student_id
                                     and shi.eff_term <= term)
         group by term, student_id, pm.credits, pm.hours
        )
 order by term, student_id

Solution 22 - Sql

I like my SQL to be formatted like so, though as long as the intent is easily readable, most any format will work. I just really hate seeing statements created in the query designer and then left that way. If I am editing someone else procedure/view/function/trigger etc.., I will try to maintain the formatting already used (Unless it is really bad, then I will reformat the whole thing).

Select Statement

SELECT ST.ColumnName1, JT.ColumnName2, SJT.ColumnName3
  FROM SourceTable ST INNER JOIN
       JoinTable JT ON JT.SourceTableID = ST.SourceTableID 
       INNER JOIN
       SecondJoinTable SJT ON ST.SourceTableID = SJT.SourceTableID
                          AND JT.Column3 = SJT.Column4
WHERE (ST.SourceTableID = X)
  AND (JT.ColumnName3 = Y);

Update Statement

UPDATE TargetTable SET
       ColumnName1 = @value,
       ColumnName2 = @value2
 WHERE (Condition1 = @test);

Insert Statement

INSERT INTO TargetTable 
           (
             ColumnName1,
             ColumnName2,
             ColumnName3
           ) 
           values 
           (
             @value1,
             @value2,
             @value3
           );

Solution 23 - Sql

My preferred style:

SELECT
  ST.ColumnName1,
  JT.ColumnName2,
  SJT.ColumnName3
FROM
  SourceTable ST
INNER JOIN
  JoinTable JT
ON
  JT.SourceTableID = ST.SourceTableID
INNER JOIN
  SecondJoinTable SJT
ON
  ST.SourceTableID = SJT.SourceTableID
WHERE
  ST.SourceTableID = X
AND
  JT.ColumnName3 = Y
AND
  JT.Column3 = SJT.Column4

Solution 24 - Sql

SELECT st.ColumnName1
      ,jt.ColumnName2
      ,sjt.ColumnName3
FROM   SourceTable st
JOIN   JoinTable jt ON jt.SourceTableID = st.SourceTableID
JOIN   SecondJoinTable sjt ON SstT.SourceTableID = sjt.SourceTableID
                              AND jt.Column3 = sjt.Column4
WHERE  st.SourceTableID = X
       AND jt.ColumnName3 = Y

I use all caps for the actions words, joins or clauses, they stand out better. JOIN is the same as INNER JOIN so INNER does not need to be written out, it's assumed, write OUTER JOIN or LEFT JOIN when you need it. I also use lowere case for my alias names. Common out front cause if you comment out the last column you are stuck with a comma above and the query fails.

Solution 25 - Sql

A hundred answers here already, but after much toing and froing over the years, this is what I've settled on:

SELECT      ST.ColumnName1
          , JT.ColumnName2
          , SJT.ColumnName3
 
FROM        SourceTable       ST
JOIN        JoinTable         JT  ON  JT.SourceTableID  =  ST.SourceTableID
JOIN        SecondJoinTable  SJT  ON  ST.SourceTableID  =  SJT.SourceTableID
                                  AND JT.Column3        =  SJT.Column4

WHERE       ST.SourceTableID  =  X
AND         JT.ColumnName3    =  Y

I know this can make for messy diffs as one extra table could cause me to re-indent many lines of code, but for my ease of reading I like it.

Solution 26 - Sql

This is my personal SQL style guide. It is based on a couple of others, but has a few main stylistic features - lowercase keywords, no extraneous keywords (e.g. outer, inner, asc), and a "river".

Example SQL looks like this:

-- basic select example
select p.Name as ProductName
     , p.ProductNumber
     , pm.Name as ProductModelName
     , p.Color
     , p.ListPrice
  from Production.Product as p
  join Production.ProductModel as pm
    on p.ProductModelID = pm.ProductModelID
 where p.Color in ('Blue', 'Red')
   and p.ListPrice < 800.00
   and pm.Name like '%frame%'
 order by p.Name

-- basic insert example
insert into Sales.Currency (
    CurrencyCode
    ,Name
    ,ModifiedDate
)
values (
    'XBT'
    ,'Bitcoin'
    ,getutcdate()
)

-- basic update example
update p
   set p.ListPrice = p.ListPrice * 1.05
     , p.ModifiedDate = getutcdate()
  from Production.Product p
 where p.SellEndDate is null
   and p.SellStartDate is not null

-- basic delete example
delete cc
  from Sales.CreditCard cc
 where cc.ExpYear < '2003'
   and cc.ModifiedDate < dateadd(year, -1, getutcdate())

Solution 27 - Sql

I think that having a good formatting rules are really important because you can spot and fix bugs easily. As it's said - "You’re writing code once, this code is read then 10000000 of times", so it always good to spend some time on formatting. The primary goals are:

  • Make your code easier to read and understand
  • Minimize the effort required to maintain or extend your code
  • Reduce the need for users and developers of a system to consult secondary documentation sources such as code comments or software manuals

Some rules I always use:

  • Always use . notation
  • Always use alias before column, so . notation
  • I put and and or to the end of the line
  • Don't use unnecessary brackets
  • Don't use UPPERCASE
  • Usually prefer using CTE to nested subqueries
  • As an example, here how I'd format query used as an example in this question:

    select
        ST.ColumnName1,
        JT.ColumnName2,
        SJT.ColumnName3
    from <schema>.SourceTable as ST
        inner join <schema>.JoinTable as JT on
            ST.SourceTableID = JT.SourceTableID
        inner join <schema>.SecondJoinTable as SJT on
            SJT.SourceTableID = ST.SourceTableID and
            SJT.Column4 = JT.Column3
    where
        ST.SourceTableID = X and
        JT.ColumnName3 = Y
    

    And "students" query:

    select
        term,
    	student_id,
        case
            when (ft_credits > 0 and credits >= ft_credits) or (ft_hours_per_week > 3 and hours_per_week >= ft_hours_per_week) then 'F'
            else 'P'
        end as [status]
    from (
        select
    		a.term,
    		a.student_id,
            pm.credits as ft_credits,
            pm.[hours] as ft_hours_per_week,
            sum(a.credits) as credits,
            sum(a.hours_per_week) as hours_per_week
        from (
    		select
    			e.term, e.student_id, NVL(o.credits, 0) credits,
                case
                    when NVL(o.weeks, 0) > 5 then
    					(NVL(o.lect_hours, 0) + NVL(o.lab_hours, 0) + NVL(o.ext_hours, 0)) / NVL(o.weeks, 0)
                    else
    					0
                end as hours_per_week
    		from enrollment as e
                inner join offering as o using (term, offering_id)
                inner join program_enrollment as pe on pe.student_id = e.student_id and pe.term = e.term and pe.offering_id = e.offering_id
    		where
    			e.registration_code Not in ('A7', 'D0', 'WL')
    	) as a
    		inner join student_history as sh using (student_id)
    		inner join program_major as pm on pm._major_code = sh.major_code_1 and pm.division_code = sh.division_code_1
        where
    		sh.eff_term = 
    			(
    				select max(eff_term)
                    from student_history as shi
                    where
    					shi.student_id = sh.student_id and
                        shi.eff_term <= term
                 )
        group by
    		a.term,
    		a.student_id,
    		pm.credits,
    		pm.[hours]
    ) as a
    order by
    	term,
    	student_id
    

Solution 28 - Sql

It appears that most of you still work on monitors that only support 800x600. My monitors will do 1920x1080, so I want to use up all that space to the right.

how about this:

select col1, col2, col3
, case when x = 1 then 'answer1'
       else 'answer2'
  end
, col4, col5, col6, col7
from table1 t1
inner join table2 t2 on t1.col1 = t2.col1 and t1.col2 and t2.col2
where t1.col5 = 19 and t1.col7 = 'Bill Gates'


       

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimboView Question on Stackoverflow
Solution 1 - SqlJohn EmeresView Answer on Stackoverflow
Solution 2 - SqlyukondudeView Answer on Stackoverflow
Solution 3 - SqlJohn SansomView Answer on Stackoverflow
Solution 4 - SqlRossBilleView Answer on Stackoverflow
Solution 5 - SqlError_2646View Answer on Stackoverflow
Solution 6 - SqlddaaView Answer on Stackoverflow
Solution 7 - SqlBen LaanView Answer on Stackoverflow
Solution 8 - SqlWouterView Answer on Stackoverflow
Solution 9 - SqlAdam RalphView Answer on Stackoverflow
Solution 10 - SqlTom HView Answer on Stackoverflow
Solution 11 - SqldthreeView Answer on Stackoverflow
Solution 12 - SqlpwilcoxView Answer on Stackoverflow
Solution 13 - SqlRuss CamView Answer on Stackoverflow
Solution 14 - SqlMrTellyView Answer on Stackoverflow
Solution 15 - SqlDanielView Answer on Stackoverflow
Solution 16 - Sqluser1400745View Answer on Stackoverflow
Solution 17 - SqldlinkView Answer on Stackoverflow
Solution 18 - SqlAeternusMentiView Answer on Stackoverflow
Solution 19 - SqlCodeZilaView Answer on Stackoverflow
Solution 20 - SqlSherlockSpreadsheetsView Answer on Stackoverflow
Solution 21 - SqlrageitView Answer on Stackoverflow
Solution 22 - SqlLarry GView Answer on Stackoverflow
Solution 23 - SqlBrady HoltView Answer on Stackoverflow
Solution 24 - SqlDanTheManView Answer on Stackoverflow
Solution 25 - SqlCodemonkeyView Answer on Stackoverflow
Solution 26 - Sqlmattmc3View Answer on Stackoverflow
Solution 27 - SqlRoman PekarView Answer on Stackoverflow
Solution 28 - SqlBill J BlenderView Answer on Stackoverflow