web-dev-qa-db-fra.com

Normes de formatage SQL

Dans mon dernier emploi, nous travaillions sur une application très lourde en bases de données et j’ai développé des normes de formatage afin que nous puissions tous écrire du code SQL avec une présentation commune. Nous avons également développé des normes de codage, mais celles-ci étant plus spécifiques à une plate-forme, je ne les aborderai pas ici.

Je suis intéressé de savoir ce que les autres utilisent pour les normes de formatage SQL. Contrairement à la plupart des environnements de codage, je n'ai pas trouvé beaucoup de consensus en ligne pour eux.

Pour couvrir les principaux types de requêtes:

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

Il y avait un certain désaccord sur les sauts de ligne après select, from et where. L'intention sur la ligne de sélection est d'autoriser d'autres opérateurs tels que "top X" sans modifier la mise en page. Par la suite, le simple fait de conserver un saut de ligne cohérent après les éléments de requête clés semblait offrir un bon niveau de lisibilité. 

Supprimer le saut de ligne après les variables from et where constituerait une révision compréhensible. Cependant, dans les requêtes telles que la update ci-dessous, nous voyons que le saut de ligne après la where nous donne un bon alignement de colonnes. De même, un saut de ligne après le group by ou le order by permet de garder la disposition de nos colonnes claire et facile à lire.

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

Enfin, une insert:

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

Dans la plupart des cas, ils ne s'écartent pas très loin de la manière dont MS L'analyseur de requête SQL Server Management Studio / écrit en SQL, mais ils do diffèrent.

J'ai hâte de voir s'il existe un consensus au sein de la communauté Stack Overflow sur ce sujet. Je suis constamment étonné du nombre de développeurs qui peuvent suivre la mise en forme standard d’autres langues et qui deviennent soudainement tellement aléatoires en touchant SQL.

51
Timbo

Je suis d'avis que tant que vous pouvez lire le code source facilement, le formatage est secondaire. Tant que cet objectif est atteint, il est possible d’adopter un bon nombre de styles de mise en page.

Le seul autre aspect important pour moi est que, quelle que soit la disposition/le style de codage que vous choisissez d’adopter dans votre magasin, veillez à ce qu’il soit utilisé systématiquement par tous les codeurs.

Juste pour votre information, voici comment je présenterais l'exemple que vous avez fourni, juste ma préférence pour la mise en page. Il est à noter que la clause ON se trouve sur la même ligne que join, seule la condition de jointure principale est répertoriée dans la jointure (c'est-à-dire la correspondance de clé) et les autres conditions sont déplacées vers la clause 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

Un conseil: procurez-vous une copie de Invite SQL de Red Gate . Vous pouvez personnaliser l'outil pour utiliser vos préférences de mise en page souhaitées, puis les codeurs de votre boutique peuvent tous l'utiliser pour s'assurer que les mêmes normes de codage sont adoptées par tout le monde.

16
John Sansom

Réponse tardive, mais j'espère utile.

Mon expérience au sein de l’équipe de développement, c’est que vous pouvez définir toutes les normes de votre choix, mais le problème est de les appliquer ou de les rendre très faciles à mettre en œuvre.

En tant que développeurs, nous créons parfois quelque chose qui fonctionne et disons «Je le formaterai plus tard», mais cela ne vient jamais plus tard.

Initialement, nous utilisions SQL Prompt (c’était génial) pour cela, mais nous sommes ensuite passés à ApexSQL Refactor , car c’est un outil gratuit.

22
John Emeres

Je suis en retard pour la fête, mais je vais simplement ajouter mon style de formatage préféré, que j'ai dû apprendre dans les livres et les manuels: c'est compact. Voici l'exemple de déclaration 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

En bref: indentation de 8 espaces, mots-clés en majuscules (bien que SO les colorent mieux en minuscules), pas de camelcase (inutile sur Oracle) et sauts de ligne si nécessaire.

La UPDATE:

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

Et la INSERT:

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

Maintenant, laissez-moi être le premier à admettre que ce style a ses problèmes. Le retrait de 8 espaces signifie que ORDER BY et GROUP BY alignent le retrait, ou divisent le mot BY par lui-même. Il serait également plus naturel d'indenter l'intégralité du prédicat de la clause WHERE, mais j'aligne généralement les opérateurs AND et OR dans la marge de gauche. L'indentation après les lignes INNER JOIN encapsulées est également quelque peu arbitraire.

Mais pour une raison quelconque, je le trouve toujours plus facile à lire que les alternatives.

Je terminerai avec l'une de mes créations les plus complexes de ce dernier utilisant ce style de formatage. À peu près tout ce que vous rencontrerez dans une déclaration SELECT apparaît dans celle-ci. (Il a également été modifié pour dissimuler ses origines et j'ai peut-être commis des erreurs en le faisant.)

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

Cette abomination calcule si un étudiant est à temps plein ou à temps partiel dans une période donnée. Indépendamment du style, celui-ci est difficile à lire.

16
yukondude

Agréable. En tant que programmeur Python, voici mes préférences:

Les sauts de ligne après select, from et where uniquement lorsque cela est nécessaire pour la lisibilité.

Lorsque le code peut être plus compact et également lisible, je préfère généralement la forme plus compacte. Le fait de pouvoir intégrer plus de code dans un écran améliore la productivité.

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

En fin de compte, ce sera un jugement qui sera fait lors de la révision du code.

Pour insert, je placerais la parenthèse différemment:

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

Le raisonnement pour cette mise en forme est que si SQL utilisait l'indentation pour la structure de bloc (comme Python), la parenthèse ne serait pas nécessaire. Donc, si l'indentation est utilisée de toute façon, les parenthèses devraient avoir un effet minimum sur la mise en page. Ceci est réalisé en les plaçant au bout des lignes.

4
ddaa
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

Utilise beaucoup plus de lignes que beaucoup d'exemples ici, mais j'estime que c'est beaucoup plus facile à comprendre, permet de supprimer rapidement les colonnes/clauses/tables. Il est utile de tirer parti d’un moniteur orienté verticalement.

3
RossBille

J'ai tendance à utiliser une mise en page similaire à la votre, même si je vais même quelques pas plus loin, par exemple:

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

Cela semble peut-être un peu exagéré au début, mais à mon humble avis, l’utilisation de la tabulation de cette manière donne la mise en page la plus propre et la plus systématique compte tenu de la nature déclarative de SQL.

Vous allez probablement vous retrouver avec toutes sortes de réponses ici. En fin de compte, cela dépend des préférences personnelles ou convenues par l'équipe.

2
Adam Ralph

Je travaille sur l'écriture d'un formateur SQL open-source (SQL-Server uniquement à ce stade) en C #, donc je lui ai posé les requêtes ci-dessus.

Il utilise une stratégie similaire à celle du PO, à savoir que chaque «section» comporte des éléments enfants mis en retrait par-dessous. Si nécessaire, j'ajoute un espace blanc entre les sections pour plus de clarté. Elles ne seront pas ajoutées s'il n'y a pas de jointures ou si les conditions sont minimales.

Résultat:

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
2
Ben Laan

En retard, mais je vais jeter mon chapeau dans le ring. L'écriture prend un peu plus de temps, mais je constate que des motifs émergent avec l'alignement vertical, ce qui le rend très lisible une fois que vous y êtes habitué.

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
2
Error_2646

Je me rends compte que je suis très en retard pour ce débat, mais je voudrais donner mon avis. Je suis définitivement en faveur des virgules en début de ligne. Comme tu dis Adam Ralph , il est plus facile de commenter un champ et je trouve aussi qu'il est plus difficile de rater une virgule accidentellement au début, alors que cela ne semble pas être un problème majeur. Dans le passé, j'ai passé des heures à rechercher des erreurs de syntaxe accidentelles dans de longues procédures T-SQL, où j'ai accidentellement manqué une virgule à la fin de la ligne (je suis sûr que certains d'entre vous l'ont probablement également fait). . Je suis également en faveur de l'aliasing autant que possible.

Dans l’ensemble, cependant, je réalise que tout dépend de la préférence personnelle, ce qui ne fonctionne pas pour certains ne fonctionne pas pour d’autres. Tant que vous pouvez lire le code facilement et que chaque développeur montre une certaine cohérence dans son style, je pense que c'est le plus important.

2
Daniel

Il y a beaucoup de bons points dans ce fil. La seule norme que j'ai essayé de convaincre les gens d'utiliser est de placer la virgule sur la même ligne avant chaque colonne. Ainsi:

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

Opposé à:

Select column1,
   column2,
   column3, ect...

La raison pour laquelle je préfère cette pratique est que, si nécessaire, vous pouvez commenter une ligne et qu'il n'y aura pas de problème de virgule lorsque vous l'exécuterez, car la virgule correspondante sera également commentée. Je sais que j'ai vu un autre utilisateur dans le fil qui avait également fait cela, mais je ne l'ai pas vraiment souligné. Pas une énorme révélation à apporter à la conversation mais mes deux centimes . Merci

2
AeternusMenti

Je suggérerais le style suivant, basé sur la suggestion de 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
        )
;

Avantages:
- Les commentaires sont essentiels pour rendre le code lisible et détecter les erreurs.
- L'ajout de filtres -all "on" à la jointure permet d'éviter les erreurs lors du passage d'une jointure interne à gauche.
- Placer le point-virgule sur une nouvelle ligne permet d’ajouter/commenter facilement des clauses where.

2
Wouter

J'utilise un format similaire au vôtre, sauf que je mets le mot clé ON sur la même ligne que la jointure et que je place les opérateurs AND et OR à la fin des lignes afin que tous mes critères de jointure/sélection s'alignent bien.

Bien que mon style soit similaire à celui de John Sansom, je ne suis pas d’accord sur l’inclusion de critères de jointure dans la clause WHERE. Je pense que cela devrait être avec la table jointe pour que ce soit organisé et facile à trouver.

J'ai aussi tendance à mettre des parenthèses sur les nouvelles lignes, alignées sur la ligne au-dessus, puis à indenter sur la ligne suivante, bien que pour les déclarations courtes, je puisse simplement garder les parenthèses sur la ligne d'origine. Par exemple:

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

Pour les instructions CASE, je donne une nouvelle ligne et une mise en retrait pour chaque WHEN et ELSE, et j'aligne la END sur la 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
2
Tom H

Je suis tout à fait d’accord avec vos efforts pour normaliser le formatage SQL dans votre projet et en général.

Je suis également très d'accord avec vos choix de formatage. J'ai proposé à peu près le même, sauf les déclarations "join", et avec elles les déclarations "on", un autre retrait. 

Cela ressemble beaucoup au fait que vous choisissiez des minuscules pour les mots-clés - Qui veut que ceux qui sont criés à vous. Je préfère aussi les alias de table minuscule - pour une meilleure lisibilité

Cela ressemble beaucoup au fait que vous utilisiez une petite empreinte (4). Je vais avec (3).

Je nix les termes "interne" et "externe" car ils sont inutiles.

Voici comment aurait formaté votre instruction 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
;

Merci d'avoir discuté de ça.

1
dlink

J'aime:

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

pour obtenir plus de code dans une zone d'affichage plus petite ... Je pense également que les mots clés doivent être en majuscules

1
user1400745

J'utilise Red Gate SQL ReFactor dans SSMS, mais un autre outil permettant de reformater (et qui remplace SSMS) est Apex's SQL Edit . Si vous souhaitez publier du code en ligne, vous trouverez Le simulateur SQL Simple-Talk .

1
K. Brian Kelley

Personne n'a encore terminé expressions de table communes (CTE). Ci-dessous l’intègre avec quelques autres styles que j’utilise:

@declare @tableVariable (
    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

Quelques points sur le format CTE:

  • Dans mes CTE, "with" est sur une ligne séparée et tout le reste du cte est en retrait.
  • Mes noms CTE sont longs et descriptifs. CTE peut obtenir des noms complexes et descriptifs sont très utiles.
  • Pour une raison quelconque, je préfère les verbes pour les noms CTE. Cela semble plus vivant.
  • Style similaire avec les parenthèses comme Javascript avec ses accolades. C'est aussi comme ça que je fais les accolades en C #. 

Cela simule:

func getSomeData() {

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

}

Quelques points à part le format CTE:

  • Deux onglets après "select" et d'autres mots clés. Cela laisse assez de place pour "jointure interne", "groupe par", etc. Vous pouvez voir un exemple ci-dessus où ce n'est pas vrai. Mais "un hachage interne" DEVRAIT avoir l'air laid. Néanmoins, sur ce point, je vais probablement expérimenter certains des styles ci-dessus dans le futur.
  • Les mots clés sont en minuscule. Leur couleur par IDE et leur statut d'indentation spécial les soulignent suffisamment. Je réserve en majuscule les autres éléments sur lesquels je souhaite mettre l'accent en fonction de la logique locale (des affaires).
  • S'il y a peu de colonnes, je les mets sur une ligne (getSomeData). S'il y en a un peu plus, je les verticalise (getSomeOtherData). S'il y a trop de verticalisation dans une unité, je horizontalise certaines colonnes dans la même ligne, regroupées par une logique définie localement (le dernier segment d'insertion-sélection). Par exemple, je mettrais les informations sur les écoles sur une ligne, les élèves sur une autre, etc.
  • Surtout lors de la verticalisation, je préfère les noms "varname = colname + quelquechose" à "colname + quelque chose comme varname".
  • Double le dernier point si je traite d'une déclaration de cas.
  • Si une certaine logique se prête à un style «matrice», je traiterai des conséquences du typage. C'est un peu ce qui se passe avec la déclaration de cas, où les "whens" et "then" sont alignés.

Je trouve que je suis plus calé sur mon style de CTE que d’autres domaines. Je n'ai pas expérimenté les styles plus similaires à ceux posés dans la question. Je vais probablement faire un jour et voir comment je l'aime. Je suis probablement maudit d'être dans un environnement où c'est un choix, bien que ce soit une malédiction amusante.

1
pwilcox

Si j'apporte des modifications à T-SQL déjà écrit, je suis la convention déjà utilisée (s'il en existe une). 

Si j'écris à partir de zéro ou s'il n'y a pas de convention, j'ai tendance à suivre votre convention donnée dans la question, sauf que je préfère utiliser des majuscules pour les mots-clés (juste une préférence personnelle pour la lisibilité). 

Je pense qu'avec le formatage SQL comme avec d'autres conventions de format de code, le point important est d'avoir une convention, pas ce que cette convention est (dans le domaine du sens commun bien sûr!)

1
Russ Cam

Oui, je vois bien l’utilité de disposer votre sql d’une manière rigoureusement définie, mais la convention de nommage et votre intention sont bien plus importantes. Comme 10 fois plus important.

Basé sur le fait que mes angoisses sont des tables préfixées par tbl, et des procédures stockées préfixées par sp - nous savons qu'il s'agit de tables et de SP. Nommer des objets de base de données est beaucoup plus important que le nombre d'espaces. 

Juste ma valeur de 0,02 $

1
MrTelly

Le nombre d'opinions divergentes est effrayant. Voici ce que mon organisation utilise:

 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

Le maintien du retrait de 8 caractères est la clé de la lisibilité à mon humble avis.

0
dthree

Mieux vaut tard que jamais. J'utilise un style différent et l'ai adopté chez un très bon développeur SQL avec lequel j'avais l'habitude de travailler. J'aligne à droite les mots clés et je n'utilise pas les lettres MAJUSCULES pour faciliter la saisie. Les mots-clés seront mis en évidence par l'éditeur et je ne vois pas la nécessité de les mettre en majuscules, sauf si vous effectuez beaucoup de modifications dans des éditeurs de texte qui ne prennent pas en charge les fonctionnalités de mise en évidence des mots-clés. Je n'essaie pas de le rendre compact, mais plutôt plus lisible et aligné verticalement autant que possible. Voici un exemple de réponse choisie à partir de @BenLaan écrite dans mon 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

Essayer de mettre en conformité toute l'équipe pour suivre le même modèle de formatage est la chose la plus difficile. Je suivrais n'importe quel format, si tout le monde suivait la même chose, mais cela n'a jamais été la même histoire.

UPDATE: Réécriture de l’une des questions complexes mentionnées dans les précédents messages:

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
rageit

J'aime que mon code SQL soit formaté de la sorte, bien que tant que l'intention est facilement lisible, la plupart des formats fonctionnent. Je déteste vraiment voir les déclarations créées dans le concepteur de requêtes et laissées de cette façon. Si je modifie une autre procédure/vue/fonction/déclencheur, etc., je vais essayer de conserver le formatage déjà utilisé (à moins que ce soit vraiment mauvais, je reformaterai le tout).

Choisir une déclaration

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

Mise à jour de la déclaration

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

Insérer une déclaration

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

Je pense qu’avoir de bonnes règles de formatage est vraiment important car vous pouvez facilement repérer et corriger les bugs. Comme il est dit - "Vous écrivez du code une fois, ce code est lu 10000000 fois de fois", il est donc toujours agréable de passer du temps sur le formatage. Les objectifs principaux sont:

  • Rendez votre code plus facile à lire et à comprendre
  • Minimiser les efforts requis pour maintenir ou étendre votre code
  • Réduire le besoin pour les utilisateurs et les développeurs d'un système de consulter des sources de documentation secondaires telles que des commentaires de code ou des manuels de logiciels

Quelques règles que j'utilise toujours:

  • Toujours utiliser. notation
  • Toujours utiliser alias avant column, donc. notation
  • Je mets and et or à la fin de la ligne
  • Ne pas utiliser les parenthèses désagréables
  • Ne pas utiliser les majuscules
  • Préfèrent généralement cte aux sous-requêtes imbriquées

Par exemple, voici comment la requête de formatage utilisée comme exemple dans cette 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

Et "étudiants" requête:

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
Roman Pekar

Ma réponse sera semblable à la réponse acceptée par John Sansom answered Feb 6 '09 at 11:05. Cependant, je vais démontrer quelques options de formatage en utilisant le plugin SQLInForm dans NOTEPAD ++ , par opposition à sa réponse avec l’invite SQL de Red Gate. 

Le plugin SQLInForm a 5 profils différents que vous pouvez configurer. Dans le profil, de nombreux paramètres sont disponibles dans les versions FREE et PAID. Une liste exhaustive est ci-dessous et vous pouvez voir leur plugin-help-general-options page en ligne. 

Au lieu de me perdre dans mes préférences, j’ai considéré qu’il serait utile de présenter les options SQLInForm disponibles. Certaines de mes préférences sont également indiquées ci-dessous. À la fin de mon message se trouve le code SQL formaté utilisé dans le message d'origine (original VS format1 VS format2). 

En lisant d'autres réponses ici, il semble que je sois dans la minorité sur deux ou trois choses. J'aime leading commas ( Short Video Here ) - IMO, il est beaucoup plus facile à lire lorsqu'un nouveau champ est sélectionné. Et aussi j'aime mon Column1 with linebreak et pas à côté du SELECT. 


Voici un aperçu de certaines de mes notes de préférences, en considérant une instruction SELECT. Je voudrais ajouter des captures d'écran de toutes les 13 sections; Mais cela fait beaucoup de captures d'écran et je vous encourage à la version gratuite - prenez quelques captures d'écran et testez les contrôles de format. Je testerai bientôt l'édition Pro. Mais en fonction des options proposées, il semble que ce sera vraiment utile et pour seulement 20 $. 

SQLInForm Notepadd ++: Options et préférences

1. Général (gratuit) 

DB: tout SQL, DB2/UDB, Oracle, MSAccess, SQL Server, Sybase, MYSQL, PostgreSQL, Informix, Teradata, Netezza SQL 

[Smart Indent] = FALSE 

2. Couleurs (gratuit) 

3. Mots-clés (PRO) 

[Upper/LowerCase]> Mots-clés 

4. Linebreaks> Lists (gratuit) 

[Avant la virgule] = VRAI 5

[Déplacez la virgule 2 colonnes vers la gauche] = FALSE 

5. Linebreaks> Sélectionnez (PRO) 

[JOIN> After JOIN] = FALSE 

[JOIN> Before ON] = FALSE 

(pas de changement) -> [JOIN> Indent JOIN]; [JOIN> After ON] 

6. Linebreaks> Ins/Upd/Del (PRO) 

7. Linebreaks> Conditions (PRO) 

CASE Instruction -> [WHEN], [THEN], [ELSE]… veulent certainement jouer avec ces paramètres et choisissez un bon 

8. Alignement (PRO) 

(pas de changement) -> [JOIN> Indent JOIN]; [JOIN> After ON] 

9. Espaces blancs (PRO) 

(modifier?) Lignes vides [Supprimer tout] = VRAI; [Garde tout]; [Gardez un] 

10. Commentaires (PRO) 

(change?) Line & Block -> [Linebreak avant/après le bloc Commentaires] = TRUE; [Modifier les commentaires de ligne en bloc]; [Block into Line] 

11. Stored Proc (PRO) 

12. Avancé (PRO) 

(Peut être utile) Extraire le code SQL du code du programme -> [ExtractSQL] 

13. Licence


Code SQL

Le format de requête d'origine.

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

FORMAT PRÉFÉRÉ DE LA CONVERSION (option n ° 1: JOIN no line line)

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

FORMAT PRÉFÉRÉ DE CONVERSION (option n ° 2: JOIN avec 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

J'espère que cela t'aides. 

0
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

J'utilise des majuscules pour les actions mots, jointures ou clauses, elles se détachent mieux. JOIN est identique à INNER JOIN, donc INNER n'a pas besoin d'être écrit, c'est supposé, écrivez OUTER JOIN ou LEFT JOIN quand vous en avez besoin. J'utilise également des cas bas pour mes noms d'alias. Généralement, parce que si vous commentez la dernière colonne, vous êtes bloqué par une virgule et la requête échoue. 

0
DanTheMan

Ceci est mon guide de style SQL personnel . Il est basé sur quelques autres, mais présente quelques caractéristiques stylistiques principales: mots clés minuscules, aucun mot clé étranger (par exemple, outer, inner, asc) et un "fleuve".

Exemple SQL ressemble à ceci:

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

Mon style préféré:

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
Brady

C’est le format que j’utilise . S'il vous plait, commentez s’il peut être amélioré.

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
CodeZila

Une centaine de réponses ici déjà, mais après beaucoup de va-et-vient au fil des ans, voici ce sur quoi je suis tombé:

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

Je sais que cela peut créer des différences désordonnées, car une table supplémentaire pourrait me forcer à réindenter plusieurs lignes de code, mais pour ma facilité de lecture, j'aime bien.

0
Codemonkey