Стандарты форматирования 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 ]

1 голос
/ 20 ноября 2015

Количество разных мнений страшно. Вот что использует моя организация:

 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-символьного отступа является ключом к читабельности ИМХО.

0 голосов
/ 08 августа 2018

Это формат, который я использую. Пожалуйста, прокомментируйте, если это может быть лучше.

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
0 голосов
/ 16 ноября 2017

Здесь уже сто ответов, но после долгих лет работы я остановился на этом:

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

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

0 голосов
/ 14 июня 2017
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, когда это необходимо Я также использую нижний регистр для своих псевдонимов. Общая внешняя причина, если вы закомментируете последний столбец, который застряли с запятой выше, и запрос завершится неудачно.

0 голосов
/ 13 июня 2017

Мой предпочтительный стиль:

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
0 голосов
/ 15 августа 2014

Лучше поздно, чем никогда. Я использую другой стиль и перенял его у очень хорошего разработчика SQL, с которым я работал. Я выравниваю ключевые слова по правому краю и не использую буквы UPPERCASE для простоты ввода. Ключевые слова будут выделены редактором, и я не вижу необходимости, чтобы они были в верхнем регистре, если вы не выполняете много редактирования в текстовых редакторах, которые не поддерживают функции выделения ключевых слов. Я не пытаюсь сделать его компактным, а как можно более читаемым и выровненным по вертикали. Вот пример выбора, взятого из ответа @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

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

UPDATE: Переписать один из сложных запросов, упомянутых в предыдущих постах:

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
0 голосов
/ 02 июня 2015

Я думаю, что хорошие правила форматирования очень важны, потому что вы можете легко находить и исправлять ошибки Как говорится: «Вы пишете код один раз, этот код читается потом 10000000 раз», поэтому всегда полезно потратить некоторое время на форматирование. Основные цели:

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

Некоторые правила, которые я всегда использую:

  • Всегда используйте. обозначение
  • Всегда используйте псевдоним перед столбцом, поэтому. обозначение
  • Я положил and и or в конец строки
  • Не используйте ненужные скобки
  • Не используйте UPPERCASE
  • Обычно предпочитают 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
0 голосов
/ 28 февраля 2015

Мне нравится, что мой 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
           );
0 голосов
/ 17 февраля 2015

Похоже, что большинство из вас все еще работают на мониторах, которые поддерживают только 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'
...