【问题标题】:SQL formatting standards [closed]SQL 格式化标准 [关闭]
【发布时间】:2010-10-05 21:56:15
【问题描述】:

在我的上一份工作中,我们开发了一个非常依赖数据库的应用程序,并且我开发了一些格式标准,以便我们都可以使用通用布局编写 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

selectfromwhere 之后的换行存在一些分歧。选择行的目的是允许其他操作符,例如“top X”而不改变布局。在此之后,在关键查询元素之后简单地保持一致的换行似乎会产生良好的可读性。

fromwhere 之后删除换行符是可以理解的修订。但是,在下面的update 等查询中,我们看到where 之后的换行符为我们提供了良好的列对齐。同样,group byorder by 之后的换行可以使我们的列布局清晰易读。

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

最后是insert

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

在大多数情况下,这些与 MS SQL Server Managements Studio / 查询分析器写出 SQL 的方式相差不大,但是它们确实不同。

我期待看到 Stack Overflow 社区对此话题是否有任何共识。我一直很惊讶有多少开发人员可以遵循其他语言的标准格式,并且在使用 SQL 时突然变得如此随意。

【问题讨论】:

  • 我倾向于将逗号放在列名和值之前。它使阅读更容易。
  • 将逗号放在列名之前还可以更轻松地注释掉该行代码,而不必担心删除前一行的逗号。
  • @DaMartyr - 明白,我见过很多。但是我是否认为它只在注释掉列表中的第一行或最后一行时会有所不同,所以总体上没有太大区别?
  • 不,你的想法没有错,但是当它是列表中的第一个或最后一个值时,除了添加评论之外,你还必须更改其他内容,而如果你开头有 ht 逗号,注释就足够了。
  • 把逗号放在开头,把第一行注释掉的时候,是不是还要去掉第二个select值上的逗号?似乎您只是将问题从最后一个值转移到第一个值......

标签: sql sql-server formatting standards coding-style


【解决方案1】:

答案较晚,但希望有用。

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

作为开发人员,我们有时会创建一些可行的东西,然后说“我稍后会格式化它”,但后来永远不会出现。

最初,我们为此使用了 SQL Prompt(非常棒),但后来改用 ApexSQL Refactor,因为它是免费工具。

【讨论】:

【解决方案2】:

我认为,只要您可以轻松阅读源代码,格式是次要的。只要实现了这个目标,就有很多不错的布局风格可以采用。

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

仅供参考,以下是我将如何展示您提供的示例,只是我的布局偏好。需要特别注意的是,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

提示,从Red Gate 获取SQL Prompt 的副本。您可以自定义该工具以使用您想要的布局偏好,然后您商店中的编码员都可以使用它来确保每个人都采用相同的编码标准。

【讨论】:

  • "只有主连接条件列在连接中(即键匹配),其他条件移动到 where 子句。使用内部连接,这没关系。如果您将 on 子句中所需的条件移至 where 子句,则外部连接的含义会发生变化。
【解决方案3】:

我迟到了,但我只会添加我喜欢的格式样式,我一定是从书籍和手册中学到的:它很紧凑。这是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

简而言之:8 空格缩进,大写关键字(尽管 SO 小写时它们的颜色更好),没有驼峰(在 Oracle 上毫无意义),并且在需要时换行。

UPDATE:

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

还有INSERT

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

现在,让我第一个承认这种风格有它的问题。 8 个空格的缩进意味着ORDER BYGROUP 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

这种可憎的方法会计算学生在给定学期内是全日制还是非全日制。不管风格如何,这个都很难读。

【讨论】:

    【解决方案4】:

    晚了,但我会把帽子扔进擂台。写起来需要更长的时间,但我发现模式是垂直对齐的,一旦你习惯了它就会变得非常可读。

    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
    

    【讨论】:

    • 我承认它看起来确实更具可读性......但看起来写起来也很痛苦
    【解决方案5】:

    很好。作为一名 Python 程序员,以下是我的偏好:

    selectfromwhere 之后的换行符仅在需要可读性时使用。

    当代码可以更紧凑且可读性更高时,我通常更喜欢更紧凑的形式。能够在一屏中容纳更多代码可以提高工作效率。

    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
    

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

    对于insert,我会以不同的方式放置括号:

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

    这种格式的原因是,如果 SQL 对块结构使用缩进(如 Python),则不需要括号。因此,如果无论如何都使用缩进,那么括号对布局的影响应该最小。这是通过将它们放在行尾来实现的。

    【讨论】:

    • 我更喜欢:插入 TargetTabel( ColumnName1 , ColumnName2 , ColumnName3 这样我就可以重新标记其中一列,而无需重新格式化插入 TargetTable( ColumnName1 --, ColumnName2 , ColumnName3
    【解决方案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
    

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

    【讨论】:

    • 这种方法的一个缺点是如果您将 table2 更改为 schema.long_table_name。您将不得不重新调整整个查询。此外,随着其他行上的空白增加,左右列变得难以匹配。
    【解决方案7】:

    我正在用 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
    

    【讨论】:

    • 对我来说,这看起来是所有建议中最易读的。我喜欢关键字与右侧对齐的方式,以及列/表名称与左侧对齐的方式。但是,不幸的是,手动使用这种格式需要大量的 'space' 'space' 'space' 才能使对齐正确,因为 'tabs' 将文本向左对齐,而不是向右对齐。
    • 嗨,这是在 Github 上吗?我正在寻找与此类似的东西,并使用与您几乎相同的样式。
    • @bjpelcdev 是的 - 甚至包括一个 SSMS 插件参见 - github.com/benlaan/sqlformat
    • 如果你想出一个格式化程序,如果你让它可配置,接受度会高得多。只需阅读此主题中的所有 cmets / 答案,您就会知道需要什么。
    【解决方案8】:

    根据 John 的建议,我建议采用以下样式:

    /*
    <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
            )
    ;
    

    优点:
    - 注释是使代码具有可读性和检测错误的重要组成部分。
    - 在连接中添加 -all- "on"-filters 可避免从内连接更改为左连接时出错。
    - 将分号放在换行符上可以轻松添加/注释 where 子句。

    【讨论】:

      【解决方案9】:

      我倾向于使用类似于你的布局,尽管我什至更进一步,例如:

      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
      

      也许一开始它看起来有点过头了,但恕我直言,鉴于 SQL 的声明性性质,以这种方式使用制表提供了最干净、最系统的布局。

      您可能会在这里得到各种各样的答案。最后,这取决于个人或团队同意的偏好。

      【讨论】:

      • 我更喜欢用逗号开头。它使标注字段 --,ST.ColumnName1 更容易。在带有 ands 和 ors 的 Where 子句中也是如此。
      • 我没有得到这个注释掉的东西。如果注释掉第一个选择值怎么办?
      • 您更有可能需要在列表末尾注释掉一些行,通常包括最后一个值。第一个值通常是您几乎肯定会需要的基本值。当然,这只是一种启发式方法,但大多数情况下它确实倾向于以这种方式工作。当然,SQL 实现真的应该忽略尾随逗号,就像大多数体面的语言一样;-)
      • 通过添加一个常量表达式例如将这种可评论性的优点扩展到下一个级别(0=0) 或 (0=1) 到您的 WHERE 子句或长度 JOIN 标准,以便第一个实际条件可以在 AND / OR 之前。例如: "WHERE (0=0)" [newline] "AND ST.SourceTableID = X" 如果需要,然后注释 WHERE 的每一行。
      • @BillVo:我确信这不会影响查询速度,但恕我直言,我们不应该为了方便注释行而添加杂乱无章的内容。
      【解决方案10】:

      不同意见的数量令人恐惧。这是我的组织使用的:

       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
      

      保持 8 个字符的缩进是提高可读性恕我直言的关键。

      【讨论】:

        【解决方案11】:

        我使用类似于您的格式,除了我将 ON 关键字放在与连接相同的行,并将 ANDOR 运算符放在行尾,以便我所有的连接/选择标准排列得很好。

        虽然我的风格与 John Sansom 的风格相似,但我不同意将连接标准放在 WHERE 子句中。我认为它应该与连接表一起使用,以便它有条理且易于查找。

        我也倾向于将括号放在新行上,与上一行对齐,然后在下一行缩进,尽管对于简短的陈述,我可能只是将括号保留在原始行上。例如:

        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)
             )
        

        对于CASE 语句,我为每个WHENELSE 指定一个新行和缩进,并将ENDCASE 对齐:

        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
        

        【讨论】:

          【解决方案12】:

          还没有人完成common table expressions (CTE)。下面将它与我使用的其他一些样式结合起来:

          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
          

          关于 CTE 格式的几点说明:

          • 在我的 CTE 中,“with”位于单独的一行,而 cte 中的其他所有内容都缩进了。
          • 我的 CTE 名称很长且具有描述性。 CTE 可以获得复杂且描述性的名称非常有帮助。
          • 出于某种原因,我发现自己更喜欢 CTE 名称中的动词。让它看起来更生动。
          • 带括号的样式与带有大括号的 Javascript 类似。这也是我在 C# 中做大括号的方式。

          这模拟:

          func getSomeData() {
          
              select        st.colA1, sot.colA2
              from          someTable st
              inner join    someOtherTable sot on st.key = sot.key
          
          }
          

          除了CTE格式之外的几点:

          • “选择”和其他关键字之后的两个选项卡。这为“内部联接”、“分组依据”等留下了足够的空间。您可以在上面看到一个不正确的示例。但是“内部哈希连接”应该看起来很难看。不过,在这一点上,我将来可能会尝试上述一些样式。
          • 关键字是小写的。 IDE 对它们的着色及其特殊的缩进状态足以突出它们。我根据本地(业务)逻辑为我想强调的其他内容保留大写。
          • 如果列数很少,我将它们放在一行 (getSomeData)。如果还有更多,我将它们垂直化(getSomeOtherData)。如果一个单元中的垂直化过多,我会将一些列水平化到同一行中,并按本地定义的逻辑分组(最后的插入-选择段)。例如,我会将学校级别的信息放在一行中,将学生级别的信息放在另一行中,等等。
          • 尤其是在垂直化时,我更喜欢 sql server 的“varname = colname + something 语法”而不是“colname + something as varname”。
          • 如果我正在处理案例陈述,请将最后一点加倍。
          • 如果某种逻辑适合“矩阵”风格,我将处理打字的后果。这就是 case 语句的情况,“whens”和“then”是对齐的。

          我发现我比其他领域更确定我的 CTE 风格。没有尝试过与问题中提出的更相似的样式。可能有一天会做,看看我有多喜欢它。我可能被诅咒在一个可以选择的环境中,尽管这是一个有趣的诅咒。

          【讨论】:

            【解决方案13】:

            如果我对已编写的 T-SQL 进行更改,那么我将遵循已使用的约定(如果有的话)。

            如果我是从头开始编写或没有约定,那么我倾向于遵循问题中给出的约定,除了我更喜欢使用大写字母作为关键字(只是个人对可读性的偏好)。

            我认为 SQL 格式化和其他代码格式约定一样,重要的是要有一个约定,而不是那个约定(当然在常识范围内!)

            【讨论】:

              【解决方案14】:

              是的,我可以看到以某种严格定义的方式布置你的 sql 的价值,但命名约定和你的意图肯定要重要得多。像 10 倍重要。

              基于我最讨厌的是以 tbl 为前缀的表和以 sp 为前缀的存储过程——我们知道它们是表和 SP。 DB对象的命名远比有多少空格重要

              仅值 0.02 美元

              【讨论】:

                【解决方案15】:

                我喜欢:

                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
                

                在更小的查看区域中获取更多代码。 我也相信关键字应该大写

                【讨论】:

                  【解决方案16】:

                  这个帖子有很多优点。我一直试图说服人们使用的一个标准是将逗号放在每一列之前的同一行。像这样:

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

                  反对:

                  Select column1,
                     column2,
                     column3, ect...
                  

                  我喜欢这种做法的原因是,如果需要,您可以注释掉一行,并且在运行它时不会出现逗号问题,因为相应的逗号也被注释掉了。我知道我在线程中看到另一个用户也这样做了,但并没有真正指出这一点。不是一个巨大的启示,而是我的两分钱。 谢谢

                  【讨论】:

                  • 如果末尾有逗号,则在注释掉列表中的最后一行时只会出现逗号问题。通过将逗号放在开头,您在注释掉列表中的第一行时只会遇到逗号问题。
                  • 但是注释掉第一行会导致问题,因为有 Select 关键字。
                  • I prefer comma at the beginning-- It is much easier to read when a new field is being selected, IMO.我也认为我更喜欢 column1 在自己的行上缩进。 hackernoon.com/…
                  【解决方案17】:

                  我完全同意您为在项目中和一般情况下标准化 SQL 格式所做的努力。

                  我也非常同意您的格式选择。我想出了几乎相同的一个,除了我还缩进了'join'语句,并且用它们'on'语句再缩进一个。

                  非常类似于您在关键字上使用小写字母的事实 - 谁想要那些对您大喊大叫的人。我也更喜欢使用小写的表别名 - 以提高可读性

                  非常类似于您使用小缩进 (4) 的事实。我选择(3)。

                  我拒绝使用“内部”和“外部”这两个术语,因为它们是不必要的。

                  以下是您的 select 语句的格式:

                  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
                  ;
                  

                  感谢您讨论这个问题。

                  【讨论】:

                  • @mattmc3 很高兴你喜欢。我同意你的看法。这是我使用的 SQL 格式化标准的正式文章。 crowfly.net/sandro/?p=179
                  【解决方案18】:

                  我意识到我在这场辩论中已经很晚了,但我想谈谈我的想法。我绝对赞成在行首使用逗号。就像你说的Adam Ralph 一样,注释掉一个字段更容易,而且我也发现在开头时意外遗漏逗号更难,虽然这听起来不是一个主要问题。过去我花了几个小时试图在冗长的 T-SQL 过程中追踪意外的语法错误,我不小心错过了行尾的逗号(我相信你们中的一些人可能也这样做过) .我也赞成尽可能地使用别名。

                  不过,总的来说,我意识到这完全取决于个人喜好,对某些人有效的方法对其他人无效。只要您可以轻松阅读代码,并且每个开发人员的风格始终保持一致,我认为这是最重要的。

                  【讨论】:

                    【解决方案19】:

                    这是我使用的格式。 如果可以做得更好,请评论。

                    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
                    

                    【讨论】:

                      【解决方案20】:

                      我的答案将类似于John Sansom answered Feb 6 '09 at 11:05 接受的答案。但是,我将使用SQLInForm plugin in NOTEPAD++ 演示一些格式化选项,而不是他对 Red Gate 的 SQL Prompt 的回答。

                      SQLInForm 插件有 5 种不同的配置文件可供您设置。在配置文件中,免费和付费版本都有很多可用的设置。下面是一个详尽的列表,您可以在线查看他们的plugin-help-general-options 页面。

                      我认为展示可用的 SQLInForm 选项会很有用,而不是漫无边际地谈论我的偏好。我的一些偏好也在下面注明。在我的帖子末尾是原始帖子中使用的格式化 SQL 代码(original VS format1 VS format2)。

                      在这里阅读其他答案-在几件事上我似乎是少数。我喜欢leading commas (Short Video Here)-- IMO,选择新字段时更容易阅读。而且我喜欢我的Column1 with linebreak,而不是在 SELECT 旁边。


                      这里是我的一些偏好说明的概述,考虑到一个 SELECT 语句。我会添加所有 13 个部分的屏幕截图;但这是很多截图,我只是鼓励你使用免费版——截取一些截图,并测试格式控制。我将很快测试 Pro 版;但根据选项,它看起来真的很有帮助,而且只需 20 美元。

                      SQLInForm Notepadd++:选项和首选项

                      1.一般(免费)

                      DB:任何 SQL、DB2/UDB、Oracle、MSAccess、SQL Server、Sybase、MYSQL、 PostgreSQL、Informix、Teradata、Netezza SQL

                      [智能缩进]= FALSE

                      2。颜色(免费)

                      3.关键字(专业版)

                      [大写/小写]> 关键字

                      4. Linebreaks> 列表(免费)

                      [逗号前]=TRUE 5

                      [将逗号向左移动 2 列]= FALSE

                      5.换行符>选择(专业版)

                      [JOIN> 加入后]= FALSE

                      [JOIN> ON 之前]= FALSE

                      (无变化)--> [JOIN> 缩进 JOIN]; [加入>开启后]

                      6.换行符> Ins/Upd/Del (PRO)

                      7.换行符> 条件 (PRO)

                      CASE 声明--> [WHEN], [THEN], [ELSE] ... 肯定想玩 使用这些设置并选择一个好的

                      8.对齐(专业版)

                      (无变化)--> [JOIN> 缩进 JOIN]; [加入>开启后]

                      9.空格(专业版)

                      (更改?)空白行 [全部删除]=TRUE; [保留全部]; [留一个]

                      10.评论(专业版)

                      (更改?) Line & Block--> [Linebreak Before/After Block 评论]=真; [将行注释更改为块]; [挡进线]

                      11.存储过程 (PRO)

                      12.高级(专业版)

                      (可能有用)从程序代码中提取 SQL--> [ExtractSQL]

                      13.许可


                      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
                      

                      转换首选格式(选项 #1:加入无换行符)

                      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
                      

                      转换首选格式(选项 #2:使用换行符连接)

                      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
                      

                      希望这会有所帮助。

                      【讨论】:

                        【解决方案21】:

                        我喜欢这样格式化我的 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);
                        

                        更新声明

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

                        插入语句

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

                        【讨论】:

                          【解决方案22】:

                          我喜欢的风格:

                          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
                          

                          【讨论】:

                            【解决方案23】:
                            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
                            

                            我对动作词、连接或从句使用全部大写,它们更突出。 JOIN 和 INNER JOIN 一样,所以 INNER 不需要写出来,假设需要的时候写 OUTER JOIN 或 LEFT JOIN。我的别名也使用小写。如果您注释掉最后一列,您会遇到上面的逗号并且查询失败,这是常见的直接原因。

                            【讨论】:

                              【解决方案24】:

                              这里已经有一百个答案了,但经过多年的折腾,这就是我所决定的:

                              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
                              

                              我知道这会导致混乱的差异,因为一个额外的表可能会导致我重新缩进许多代码行,但为了便于阅读,我喜欢它。

                              【讨论】:

                              • 就我个人而言,我非常不喜欢前面的逗号符号——我会想到“可憎”之类的词。
                              • 这就是你挑剔的?不是表别名ON= 两侧的12 空格过大缩进或双倍间距?那我做得很好?
                              • 那些也是。这与我格式化查询的方式非常不同。
                              【解决方案25】:

                              迟到总比没有好。我使用了一种不同的风格,并从我曾经合作过的一位非常优秀的 SQL 开发人员那里采用了它。我右对齐关键字,我不使用大写字母以便于输入。关键字将由编辑器突出显示,除非您在不支持关键字突出显示功能的文本编辑器中进行大量编辑,否则我认为它们不需要大写。我并没有试图让它紧凑,而是尽可能地更具可读性和垂直对齐。以下是从@BenLaan 答案中选取的示例,以我的格式编写:

                              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
                              

                              试图让所有团队都遵循相同的格式模式是最困难的事情。如果其他人都遵循相同的方式,我会遵循任何格式,但它从来都不是同一个故事。

                              更新: 重写之前文章中提到的复杂查询之一:

                              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
                              

                              【讨论】:

                                【解决方案26】:

                                This is my personal SQL style guide。它基于其他几个,但有一些主要的风格特征 - 小写关键字,没有无关关键字(例如outerinnerasc)和“河流”。

                                示例 SQL 如下所示:

                                -- 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())
                                

                                【讨论】:

                                  【解决方案27】:

                                  我认为拥有良好的格式规则非常重要,因为您可以轻松发现和修复错误。正如它所说 - “你只写一次代码,这段代码会被读取 10000000 次”,所以花一些时间在格式化上总是好的。主要目标是:

                                  • 让您的代码更易于阅读和理解
                                  • 尽量减少维护或扩展代码所需的工作量
                                  • 减少系统用户和开发人员查阅二级文档资源(例如代码 cmets 或软件手册)的需要

                                  我经常使用的一些规则:

                                  • 始终使用 .符号
                                  • 总是在列之前使用别名,所以 .符号
                                  • 我把andor放到了行尾
                                  • 不要使用不必要的括号
                                  • 不要使用大写
                                  • 通常更喜欢使用 CTE 而不是嵌套子查询

                                  作为一个例子,这里我将如何格式化这个问题中用作示例的查询:

                                  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
                                  

                                  和“学生”查询:

                                  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
                                  

                                  【讨论】:

                                    【解决方案28】:

                                    看来你们中的大多数人仍在使用仅支持 800x600 的显示器。我的显示器分辨率为 1920x1080,所以我想用完右边的所有空间。

                                    这个怎么样:

                                    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'
                                    

                                    【讨论】:

                                      猜你喜欢
                                      • 2010-09-21
                                      • 2010-09-19
                                      • 2022-01-21
                                      • 1970-01-01
                                      • 2020-09-27
                                      • 2011-04-02
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多