Comment faciliter l'écriture de requêtes SQL complexes? [fermé]


42

Je trouve très difficile d'écrire des requêtes SQL complexes impliquant des jointures entre plusieurs tables (au moins 3-4) et impliquant plusieurs conditions imbriquées. Les requêtes que l'on me demande d'écrire sont facilement décrites par quelques phrases, mais peuvent nécessiter une quantité de code trompeuse. Je me trouve souvent en train d'utiliser des vues temporaires pour écrire ces requêtes, qui ressemblent à une béquille. Quels conseils pouvez-vous fournir pour faciliter ces requêtes complexes? Plus précisément, comment puis-je décomposer ces requêtes en étapes que je dois suivre pour écrire le code SQL?

Notez que je suis le code SQL que l’on me demande d’écrire fait partie des devoirs d’un cours de base de données. Je ne souhaite donc pas de logiciel qui fera le travail à ma place. Je veux réellement comprendre le code que j'écris.

Plus de détails techniques:

  • La base de données est hébergée sur un serveur PostgreSQL qui s'exécute sur la machine locale.
  • La base de données est très petite: il n'y a pas plus de sept tables et la plus grande contient moins de 50 lignes.
  • Les requêtes SQL sont transmises sans modification au serveur, via LibreOffice Base.

Les vues temporaires sont en fait très utiles car vous pouvez effectuer des tâches dans une telle table (comme des index complexes explicites) qu'il est très difficile d'indiquer à l'analyseur SQL.

Personnellement, je trouve plus facile de tricher en utilisant une interface graphique (telle que LibreOffice Base "Créer une requête en mode Création" ou Office Access "Créer"> "Création de la requête"), puis d'afficher le code SQL généré. Parfois, il est nécessaire de modifier le
code

Réponses:


49

Je me base principalement sur le fait d’essayer d’obtenir la "bonne" réponse, de sorte que vous pourriez découvrir quelques problèmes de performances. Inutile d'accélérer une requête incorrecte.

Comprendre les relations entre les tables - la plupart seront un à plusieurs. Connaître le "plusieurs" table. Identifiez les champs requis pour vos jointures.

Pensez aux scénarios de participation à GAUCHE - Sélectionnez tous les employés et leur salaire depuis le mois dernier. Et s'ils ne recevaient pas de salaire le mois dernier?

Connaître le jeu de résultats: 1) Dans une feuille de calcul, entrez manuellement au moins un enregistrement correct pour votre requête. 2) Ecrivez la requête sous une forme assez simple pour identifier le nombre d'enregistrements à renvoyer. Utilisez les deux pour tester votre requête afin de vous assurer que la jonction d'une nouvelle table ne modifie pas le résultat.

Découpez votre requête en parties gérables - Vous n'avez pas à l'écrire en une fois. Les requêtes complexes peuvent parfois être simplement un ensemble de requêtes simples.

Méfiez-vous des niveaux d'agrégation mixtes : si vous devez mettre des valeurs mensuelles, trimestrielles et cumulatives dans le même ensemble de résultats, vous devrez les calculer séparément dans des requêtes groupées sur des valeurs différentes.

Sachez quand joindre UNION Il est parfois plus facile de diviser des sous-groupes en leurs propres déclarations sélectionnées. Si vous avez une table mélangée avec des gestionnaires et d'autres employés, et que vous devez faire dans chaque colonne des instructions Case basées sur l'appartenance à l'un de ces groupes, il peut s'avérer plus simple d'écrire une requête de gestionnaire et de la lier à une requête d'employé. Chacun contiendrait sa propre logique. Devoir inclure des éléments de différentes tables dans différentes lignes est une utilisation évidente.

Formules complexes / imbriquées - Essayez d'indenter de manière cohérente et n'ayez pas peur d'utiliser plusieurs lignes. "CASE WHEN CASE WHEN CASE WHEN" va vous rendre fou. Prenez le temps de bien réfléchir. Enregistrez les calculs complexes pour la fin. Obtenez les enregistrements corrects sélectionnés en premier. Ensuite, vous attaquez des formules complexes en sachant que vous travaillez avec les bonnes valeurs. Voir les valeurs utilisées dans les formules vous aidera à repérer les zones dans lesquelles vous devez prendre en compte les valeurs NULL et où gérer l'erreur de division par zéro.

Testez souvent lorsque vous ajoutez de nouvelles tables pour vous assurer que vous obtenez toujours le jeu de résultats souhaité et que vous savez quelle jointure ou quelle clause est coupable.


1
Vraiment excellent. Je tiens à souligner de nouveau les arguments de Jeff en matière de recherche de jointures à GAUCHE, de fractionnement de requêtes complexes en requêtes plus petites et plus faciles à gérer, puis de leur combinaison. J'écris de grosses requêtes sur de grandes bases de données à peu près tous les jours et ces deux choses en particulier se présentent tout le temps. Exécutez toujours vos requêtes et sous-requêtes dès que vous le pouvez pour vous assurer d'obtenir les données que vous vous attendez à voir à chaque étape.
CodexArcanum

@ CodexArcanum - et quand vous lancez des requêtes sur le Big Data, utiliser TOP ne fait pas de mal;)
JeffO

Je suis d'accord sur chaque déclaration de votre suggestion
Alessandro Rossi

28
  1. L’indentation serait la première chose à faire, si vous ne le faites pas déjà. Non seulement il est utile même avec des requêtes simples, mais il est crucial pour les jointures et les requêtes un peu plus complexes qu’un select top 1 [ColumnName] from [TableName].

  2. Une fois mis en retrait correctement, rien n’interdit d’ ajouter des commentaires dans la requête elle-même, le cas échéant. Ne les utilisez pas trop: si le code est suffisamment explicite, ajouter des commentaires nuira à la clarté du code. Mais ils sont toujours les bienvenus pour les parties moins explicites de la requête.

    Notez que des requêtes plus longues (y compris des requêtes avec des commentaires) signifieraient une utilisation plus importante de la bande passante entre votre serveur d'applications et votre serveur de base de données. Notez également que si vous travaillez sur un produit à l'échelle de Google avec une quantité énorme de requêtes par seconde, nécessitant des performances et une utilisation des ressources exceptionnelles, la taille ajoutée par les commentaires ne changera rien pour vous en termes de performances.

  3. Appliquer le même style sur les tableaux, les colonnes, etc. facilite également la lisibilité. Lorsqu'une base de données héritée possède les tables PRODUCT, users, USERS_ObsoleteDONT_USE, PR_SHIPMENTSet HRhbYd_UU, quelqu'un fait quelque chose de très mal.

  4. L'application du même style sur les requêtes est également importante. Par exemple, si vous écrivez des requêtes pour Microsoft SQL Server et que vous avez décidé d'utiliser [TableName]plutôt que de TableNamerester, respectez-le. Si vous passez à une nouvelle ligne après un select, ne le faites pas dans seulement la moitié de vos requêtes, mais dans toutes.

  5. Ne pas utiliser* , sauf s’il existe de fortes raisons de le faire (comme if exists(select * from [TableName] where ...)dans Microsoft SQL Server). Cela *a non seulement un impact négatif sur les performances de certaines (sinon de la plupart) des bases de données, mais n’est pas non plus utile pour le développeur qui utilise votre requête. De la même manière, un développeur doit accéder aux valeurs par nom, jamais par index.

  6. Enfin, pour les sélections, il n’ya rien de mal à fournir une vue . Pour toute autre chose, les procédures stockées peuvent également être utilisées en fonction du projet et des personnes¹ avec lesquelles vous travaillez².


¹ Certaines personnes détestent les procédures stockées. D'autres ne les aiment pas pour plusieurs raisons (parfaitement valables, du moins pour eux).

² Vos collègues, les autres étudiants, votre professeur, etc.


9

Un peu dans le noir ici, mais si vous écrivez beaucoup de vues temporaires, vous ne vous êtes peut-être pas encore rendu compte que la plupart des endroits où vous pourriez placer une table dans une instruction SQL pourraient être remplacés par une requête.

Ainsi, plutôt que de joindre la table A à la vue temporaire B, vous pouvez joindre la table A à la requête que vous utilisiez comme vue temporaire B. Par exemple:

    SELECT A.Col1, A.Col2, B.Col1,B.Col2
      FROM (SELECT RealTableZ.Col1, RealTableY.Col2, RealTableY.ID as ID
              FROM RealTableZ 
   LEFT OUTER JOIN RealTableY
                ON RealTableZ.ForeignKeyY=RealTableY.ID
             WHERE RealTableY.Col11>14
            ) As B
        INNER JOIN A
                ON A.ForeignKeyY=B.ID

Cet exemple est plutôt inutile, mais devrait expliquer la syntaxe.

Pour les vues qui ne sont pas "spéciales" (indexées, partitionnées), le même plan de requête devrait être identique à celui utilisé si vous utilisiez une vue.

En ce qui concerne la rédaction, vous pouvez vérifier chaque élément pour vous assurer que vous obtenez le résultat attendu avant d'écrire l'intégralité de la requête.

Mes excuses si c'est déjà vieux chapeau pour vous.


3
Je suis assez expert en SQL et je déteste vraiment cette indentation: elle peut paraître jolie mais totalement inutile "à mon avis". Deux raisons: je ne comprends pas clairement si cette jointure externe gauche fait partie de la requête principale ou d'une sous-requête, elle nécessite un code de retouche de code et chaque fois que vous souhaitez ajouter quelques lignes, vous devez ré-embellir l'ensemble du texte. . Plan d'indentation qui nécessite seulement TABS est beaucoup plus flexible. Je n'ai pas voté contre votre réponse, mais je décourage vraiment ceux qui utilisent ce style ... surtout lorsqu'ils ont besoin de mon aide.
Alessandro Rossi

7

Au lieu des vues temporaires, utilisez la clause WITH . Cela facilite beaucoup la décomposition de requêtes volumineuses en parties plus petites lisibles.


1
Si vous utilisez un cte, sachez que la requête ne persiste que jusqu'à l'exécution de la requête suivante. Ainsi, dans certains cas, si vous utilisez le cte dans plusieurs requêtes, il peut être préférable d'utiliser une table temporaire pour les performances.
Rachel

3
  1. Familiarisez-vous avec la théorie des ensembles si vous ne l'êtes pas déjà. SQL est basé sur la théorie des ensembles et une meilleure compréhension de ceux-ci vous aidera à vous familiariser avec le fonctionnement de SQL.
  2. Pratiquez plus SQl, si vous apprenez simplement le langage SQL, il faudra du temps pour comprendre comment tout faire, quelque chose prend juste du temps avant que vous ne le compreniez vraiment. Les jointures sont un excellent exemple.
  3. Assurez-vous que les tables que vous interrogez sont bien conçues
  4. N'ayez pas peur d'utiliser des vues sur certaines requêtes, en particulier si vous avez un ensemble commun qui doit être affiné de différentes manières.

1

Comme n'importe quoi d'autre, vous voulez diviser le problème en parties gérables.

Soit dit en passant, vous résolvez des problèmes complexes.

Donc: vous voulez vérifier la sous-requête pour voir qu'elle renvoie vraiment ce que vous voulez avant d'exécuter une requête externe dessus. Vous voulez essayer une jointure minimale de chaque table à laquelle vous vous joignez afin de voir que vous y réfléchissez correctement. Des choses comme ça. Il est tout à fait irréaliste d’espérer taper le tout et obtenir exactement ce que vous voulez.

Une instruction SQL, une fois qu’elle atteint un certain niveau de complexité, est fondamentalement un petit programme en soi. Cela fait une grande différence de vraiment comprendre comment les données sont combinées, sélectionnées, filtrées et sorties.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.