SQL格式标准

Tim*_*mbo 54 sql sql-server formatting standards coding-style

在我上一份工作中,我们开发了一个数据库非常繁重的应用程序,并且我开发了一些格式化标准,以便我们都可以使用通用布局编写SQL.我们还开发了编码标准,但这些标准更具有平台特性,所以我不会在这里讨论它们.

我很想知道其他人使用什么SQL格式标准.与大多数其他编码环境不同,我没有在网上找到很多共识.

要涵盖主要查询类型:

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
Run Code Online (Sandbox Code Playgroud)

有一些分歧关于行后饲料select,fromwhere.选择行的意图是允许其他运算符,例如"top X"而不改变布局.接下来,只需在关键查询元素之后保持一致的换行符,就可以获得良好的可读性.

滴药后换行from,并where会是一个可以理解的版本.但是,在update下面的查询中,我们看到后面的换行为where我们提供了良好的列对齐.同样,换行后group byorder by保持我们的列布局清晰易读.

update
    TargetTable
set
    ColumnName1 = @value,
    ColumnName2 = @value2
where
    Condition1 = @test
Run Code Online (Sandbox Code Playgroud)

最后,一个insert:

insert into TargetTable (
    ColumnName1,
    ColumnName2,
    ColumnName3
) values (
    @value1,
    @value2,
    @value3
)
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,这些并没有偏离MS SQL Server管理工作室 /查询分析器写出SQL的方式,但它们确实有所不同.

我期待看到Stack Overflow社区中是否就此主题达成了共识.我经常惊讶于有多少开发人员可以遵循其他语言的标准格式,并在遇到SQL时突然变得如此随机.

小智 22

迟到的答案,但希望有用.

我作为大型开发团队的一员工作的经验是,您可以继续定义您喜欢的任何标准,但问题实际上是强制执行这些或使开发人员很容易实现.

作为开发人员,我们有时创建一些有用的东西然后说"我稍后会格式化",但后来永远不会出现.

最初,我们使用了SQL Prompt(很棒),但后来切换到ApexSQL Refactor,因为它是一个免费的工具.


yuk*_*ude 18

我迟到了,但我只是添加了我喜欢的格式化风格,我必须从书本和手册中学到:它很紧凑.这是示例SELECT声明:

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
Run Code Online (Sandbox Code Playgroud)

简而言之:8个空格的缩进,大写字母中的关键字(虽然小写时它们的颜色更好),没有camelcase(在Oracle上没有意义),并且在需要时换行.

UPDATE:

UPDATE  target_table
SET     column_name_1 = @value,
        column_name_2 = @value2
WHERE   condition_1 = @test
Run Code Online (Sandbox Code Playgroud)

而且INSERT:

INSERT  INTO target_table (column_name_1, column_name_2,
                column_name_3)
VALUES  (@value1, @value2, @value3)
Run Code Online (Sandbox Code Playgroud)

现在,让我成为第一个承认这种风格存在问题的人.8空格缩进意味着ORDER BY并且GROUP BY不对齐缩进,或者将单词BY本身分开.缩进WHERE子句的整个谓词也是更自然的,但我通常在左边缘对齐跟随ANDOR运算符.包裹INNER JOIN线后缩进也有些随意.

但无论出于何种原因,我仍然觉得它比其他选择更容易阅读.

我将使用这种格式化风格完成我最近的一个更复杂的创作.几乎所有你在SELECT声明中遇到的东西都出现在这一个中.(它也被改变以掩盖它的起源,我可能在这样做时引入了错误.)

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
Run Code Online (Sandbox Code Playgroud)

这种憎恶计算学生在特定学期是全职还是兼职.无论风格如何,这个都难以阅读.


Joh*_*som 17

我认为只要你能轻松阅读源代码,格式就是次要的.只要实现了这个目标,就可以采用一些好的布局样式.

对我来说唯一重要的另一个方面是,无论您选择在商店中采用何种编码布局/样式,都要确保所有编码人员始终如一地使用它.

仅供您参考,以下是我将如何呈现您提供的示例,以及我的布局首选项.特别值得注意的是,该ON子句与连接中的join主要连接条件(即密钥匹配)在同一行上,并且其他条件被移动到where子句中.

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
Run Code Online (Sandbox Code Playgroud)

一个提示,从Red Gate获取SQL Prompt的副本.您可以自定义工具以使用所需的布局首选项,然后您商店中的编码人员都可以使用它来确保每个人都采用相同的编码标准.

  • "只有主要的连接条件在连接中列出(即密钥匹配),其他条件被移动到where cluase." 使用内部连接,这是可以的.如果将on子句中所需的条件移动到where子句,则使用外连接时,含义会发生变化. (10认同)

Err*_*646 7

迟到了,但我会把我的帽子扔进戒指里。写作需要更长的时间,但我发现垂直对齐会出现模式,一旦你习惯了它就会变得非常易读。

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
Run Code Online (Sandbox Code Playgroud)


Ben*_*aan 6

我正在用 C# 编写开源 SQL 格式化程序(现阶段仅限 SQL Server),因此我通过它完成了上述查询。

它采用与 OP 类似的策略,即每个“部分”在其下方都有缩进的子元素。如果需要,我会在部分之间添加空白以帮助清晰——当没有连接或最小 where 条件时,不会添加这些空白。

结果:

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
Run Code Online (Sandbox Code Playgroud)


Ros*_*lle 6

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
Run Code Online (Sandbox Code Playgroud)

使用的行比这里的许多示例多得多,但我觉得它更容易理解,可以快速删除列/子句/表格。它有助于利用垂直定向的显示器。

  • 这种方法的一个缺点是如果将 table2 更改为 schema.long_table_name。您将不得不重新调整整个查询。此外,随着其他行上的空白增加,很难匹配左列和右列。 (3认同)

dda*_*daa 5

真好 作为Python程序员,这是我的偏好:

之后的换行符selectfrom并且where仅在需要可读性时才使用。

当代码可以更紧凑且可读性更好时,我通常更喜欢更紧凑的形式。能够在一个屏幕中容纳更多代码,从而提高了生产率。

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
Run Code Online (Sandbox Code Playgroud)

最终,这将是在代码检查期间进行的判断调用。

对于insert,我将括号放在不同的位置:

insert into TargetTable (
    ColumnName1,
    ColumnName2,
    ColumnName3)
values (
    @value1,
    @value2,
    @value3)
Run Code Online (Sandbox Code Playgroud)

这种格式的理由是,如果SQL将缩进用于块结构(如Python),则不需要括号。因此,如果仍然使用缩进,则括号应该对布局的影响最小。这是通过将它们放置在行的末尾来实现的。