Стандарты форматирования SQL - PullRequest
53 голосов
/ 06 февраля 2009

В моей последней работе мы работали над приложением, очень загруженным базой данных, и я разработал несколько стандартов форматирования, чтобы мы все писали 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

Были некоторые разногласия по поводу перевода строки после select, from и where. Цель строки выбора - разрешить другим операторам, таким как "top X", не изменять макет. Исходя из этого, простое поддержание согласованного перевода строки после ключевых элементов запроса, казалось, привело к хорошему уровню читабельности.

Сброс перевода строки после from и where будет понятной ревизией. Однако в таких запросах, как update ниже, мы видим, что перевод строки после where дает нам хорошее выравнивание столбцов. Аналогичным образом, перевод строки после group by или order 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, однако они do отличаются.

Я с нетерпением жду возможности увидеть консенсус в сообществе Stack Overflow по этой теме. Я постоянно удивляюсь, как много разработчиков могут придерживаться стандартного форматирования для других языков и внезапно становятся настолько случайными при обращении к SQL.

Ответы [ 29 ]

22 голосов
/ 12 мая 2013

Поздний ответ, но, надеюсь, полезно.

Мой опыт работы в составе большой команды разработчиков заключается в том, что вы можете пойти дальше и определить любые стандарты, которые вам нравятся, но проблема заключается в их применении или в том, что разработчикам очень легко их реализовать.

Как разработчики, мы иногда создаем что-то, что работает, а затем говорим: «Я отформатирую это позже», но позже это никогда не наступит.

Изначально мы использовали SQL Prompt (это было здорово), но затем переключились на ApexSQL Refactor , потому что это бесплатный инструмент.

17 голосов
/ 21 марта 2009

Я опаздываю на вечеринку, но я просто добавлю свой предпочтительный стиль форматирования, который я, должно быть, выучил из книг и руководств: он компактен. Вот пример 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 BY и GROUP BY либо смещают отступ, либо разбивают слово BY на себя. Также было бы более естественным сделать отступ для всего предиката предложения WHERE, но я обычно выравниваю после операторов AND и OR на левом поле. Отступ после перенесенных 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

Эта мерзость вычисляет, является ли студент полным или неполным рабочим днем ​​в данный семестр. Независимо от стиля, этот труден для чтения.

16 голосов
/ 06 февраля 2009

Я считаю, что если вы легко читаете исходный код, форматирование является второстепенным. Пока эта цель достигнута, существует ряд хороших стилей макета, которые можно принять.

Единственный другой аспект, который важен для меня, заключается в том, что какой бы макет / стиль кодирования вы ни выбрали для своего магазина, убедитесь, что он последовательно используется всеми кодировщиками.

Просто для справки, вот как я бы представил приведенный вами пример, только мои настройки макета. Особо следует отметить, что предложение 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

Один совет, получите себе копию SQL Prompt из Red Gate . Вы можете настроить инструмент так, чтобы он использовал ваши предпочтительные макеты, и тогда все кодировщики в вашем магазине смогут использовать его, чтобы гарантировать, что каждый принимает одинаковые стандарты кодирования.

5 голосов
/ 06 февраля 2009

Nice. Как программист Python, вот мои предпочтения:

Новые строки после select, from и 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

В конечном счете, это будет оценочный вызов, который будет сделан во время проверки кода.

Для insert я бы поставил круглые скобки по-другому:

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

Причина такого форматирования заключается в том, что если в SQL используется отступ для блочной структуры (например, Python), скобки не понадобятся. Таким образом, если в любом случае используется отступ, то круглые скобки должны оказывать минимальное влияние на макет. Это достигается размещением их в конце строк.

4 голосов
/ 20 января 2015

Я бы предложил следующий стиль, основанный на предложении Джона:

/*
<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» -фильтров к объединению позволяет избежать ошибок при переходе от внутреннего к левому объединению.
- Размещение точки с запятой на новой строке позволяет легко добавлять / комментировать предложения where.

3 голосов
/ 29 октября 2009

Я работаю над написанием средства форматирования SQL с открытым исходным кодом (только для SQL-Server на данном этапе) на C #, поэтому я выполняю вышеуказанные запросы через него.

Он использует стратегию, аналогичную OP, а именно, что каждый «раздел» имеет дочерние элементы с отступом под ним. Там, где это необходимо, я добавляю пробел между разделами для большей ясности - они не будут добавлены, когда нет соединений или минимально допустимые условия.

Результат:

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
3 голосов
/ 06 февраля 2009

Я склонен использовать макет, похожий на ваш, хотя я даже иду на несколько шагов дальше, например ::10000

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.

Вы, вероятно, получите здесь ответы на все вопросы. В конце концов, это зависит от личных или согласованных с командой предпочтений.

3 голосов
/ 26 июля 2017

Поздно, но я брошу свою шляпу на ринг. Запись занимает немного больше времени, но я обнаружил, что шаблоны появляются с вертикальным выравниванием, что делает его очень читабельным, когда вы к нему привыкли.

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
3 голосов
/ 19 февраля 2014
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

Использует гораздо больше строк, чем множество примеров здесь, но я чувствую, что это намного проще для понимания, позволяет быстро удалить столбцы / предложения / таблицы. Это помогает использовать преимущества вертикально ориентированного монитора.

2 голосов
/ 08 сентября 2009

Я понимаю, что очень опоздал на эту дискуссию, но я хотел бы высказать свои мысли. Я определенно поддерживаю запятые в начале строки. Как вы говорите Адам Ральф , легче закомментировать поле, и я также нахожу, что сложнее случайно пропустить запятую, когда они в начале, хотя это не кажется серьезной проблемой , В прошлом я часами пытался отследить случайные синтаксические ошибки в длинных процедурах T-SQL, где я случайно пропустил запятую в конце строки (я уверен, что некоторые из вас, вероятно, также сделали это) , Я также поддерживаю алиасинг как можно больше.

В целом, я понимаю, что все зависит от личных предпочтений, то, что работает для одних, не для других. Пока вы можете легко читать код и каждый разработчик демонстрирует некоторую последовательность в своем стиле, я думаю, что это наиболее важно.

...