Database
 sql >> Base de données >  >> RDS >> Database

Comment écrire des requêtes complexes en SQL

Les requêtes typiques au format de table SELECT * FROM ne suffisent parfois pas. Lorsque les données d'une requête ne se trouvent pas dans une table, mais dans plusieurs, ou lorsqu'il est nécessaire de spécifier plusieurs paramètres de sélection à la fois, vous aurez besoin de requêtes plus sophistiquées.

Cet article explique comment créer de telles requêtes et fournit des exemples de requêtes SQL complexes.

À quoi ressemble une requête complexe ?

Définissons d'abord les conditions de composition de la requête SQL. Vous devrez notamment utiliser les paramètres de sélection suivants :

  • les noms des tables dont vous souhaitez extraire les données ;
  • les valeurs des champs qui doivent être retournées à celles d'origine après avoir apporté des modifications à la base de données ;
  • les relations entre les tables ;
  • les conditions d'échantillonnage ;
  • les critères de sélection auxiliaires (restrictions, modes de présentation des informations, type de tri).

Pour mieux comprendre le sujet, considérons un exemple qui utilise les quatre tableaux simples suivants. La première ligne est le nom de la table qui, dans les requêtes complexes, agit comme une clé étrangère. Nous examinerons cela plus en détail avec un exemple :

Chaque table contient des lignes liées à d'autres tables. Nous expliquerons pourquoi c'est nécessaire plus loin.

Examinons maintenant la requête SQL de base :

SELECT * FROM companies WHERE companies_name %STARTSWITH 'P';

Le %STARTSWITH prédicat sélectionne les lignes commençant par le(s) caractère(s) spécifié(s).

Le résultat ressemble à ceci :

Considérons maintenant une requête SQL complexe :

SELECT 
	companies.companies_name,
	SUM(CASE WHEN call.id IS NOT NULL THEN 1 ELSE 0 END) AS calls,
	AVG(ISNULL(DATEDIFF(SECOND, calls.start_time, calls.end_time),0)) AS avgdifference
FROM companies 
LEFT JOIN offices ON offices.companies_id = companies.id
LEFT JOIN customers ON offices.id = customers.offices_id
LEFT JOIN calls ON calls.customers_id = customers.id
GROUP BY 
	companies.id,
	companies.companies_name
HAVING AVG(ISNULL(DATEDIFF(SECOND, calls.start_time, calls.end_time),0)) > (SELECT AVG(DATEDIFF(SECOND, calls.start_time, calls.end_time)) FROM calls)
ORDER BY calls DESC, companies.id ASC;

Le résultat est le tableau suivant :

Le tableau indique les entreprises, le nombre d'appels téléphoniques correspondants et leur durée approximative.

De plus, il répertorie uniquement les noms d'entreprises pour lesquelles la durée moyenne des appels est supérieure à la durée moyenne des appels dans d'autres entreprises.

Quelles sont les principales règles de création d'une requête SQL complexe ?

Essayons de créer un algorithme polyvalent pour composer des requêtes complexes.

Tout d'abord, vous devez décider des tables composées des données qui participent à la requête.

L'exemple ci-dessus concerne les sociétés et appels les tables. Si les tables contenant les données requises ne sont pas directement liées les unes aux autres, vous devez également inclure les tables intermédiaires qui les rejoignent.

Pour cette raison, nous connectons également des tables, telles que des bureaux et clients , en utilisant des clés étrangères. Par conséquent, tout résultat de la requête avec des tables de cet exemple inclura toujours les lignes ci-dessous :

SELECT 
	...
FROM companies 
LEFT JOIN offices ON offices.companies_id = companies.id
LEFT JOIN customers ON offices.id = customers.offices_id
LEFT JOIN calls ON calls.customers_id = customers.id
...;

After that, you must test the correctness of the behavior in the following part of the query:

SELECT * FROM companies 
LEFT JOIN offices ON offices.companies_id = companies.id
LEFT JOIN customers ON offices.id = customers.offices_id
LEFT JOIN calls ON calls.customers_id = customers.id;

Un tableau combiné suggère les trois points les plus importants :

  • Faites attention à la liste des champs après SELECT. L'opération de lecture des données des tables jointes nécessite que vous indiquiez le nom de la table à joindre dans le nom champ.
  • Votre requête complexe aura toujours la table principale (sociétés ). La plupart des champs sont lus à partir de celui-ci. La table jointe, dans notre exemple, utilise trois tables - bureaux , clients , et appels . Le nom est déterminé après l'opérateur JOIN.
  • En plus de spécifier le nom de la deuxième table, assurez-vous de spécifier la condition pour effectuer la jointure. Nous discuterons de cette condition plus loin.
  • La requête affichera un tableau avec un grand nombre de lignes. Il n'est pas nécessaire de le publier ici, car il affiche des résultats intermédiaires. Cependant, vous pouvez toujours vérifier vous-même sa sortie. Ceci est très important, car cela permet d'éviter les erreurs dans le résultat final.

Examinons maintenant la partie de la requête qui compare les durées d'appel au sein de chaque entreprise et entre toutes les entreprises. Nous devons calculer la durée moyenne de tous les appels. Utilisez la requête suivante :

SELECT AVG(DATEDIFF(SECOND, calls.start_time, calls.end_time)) FROM calls

Notez que nous avons utilisé le DATEDIFF fonction qui affiche la différence entre les périodes spécifiées. Dans notre cas, la durée moyenne des appels est égale à 335 secondes.

Ajoutons maintenant à la requête des données sur les appels de toutes les entreprises.

SELECT 
	companies.companies_name,
	SUM(CASE WHEN calls.id IS NOT NULL THEN 1 ELSE 0 END) AS calls,
	AVG(ISNULL(DATEDIFF(SECOND, calls.start_time, calls.end_time),0)) AS avgdifference
FROM companies 
LEFT JOIN offices ON offices.companies_id = companies.id
LEFT JOIN customers ON offices.id = customers.offices_id
LEFT JOIN calls ON calls.customers_id = customers.id
GROUP BY 
	companies.id,
	companies.companies_name
ORDER BY calls DESC, companies.id ASC;

Dans cette requête,

  • SUM (CASE WHEN calls.id IS NOT NULL THEN 1 ELSE 0 END) – pour éviter les opérations inutiles, on résume uniquement les appels existants – lorsque le nombre d'appels dans une entreprise n'est pas nul. Ceci est très important dans les grandes tables avec des valeurs nulles possibles.
  • AVG (ISNULL (DATEDIFF (SECOND, calls.start_time, calls.end_time), 0)) – la requête est identique à la requête AVG ci-dessus. Cependant, ici nous utilisons le ISNULL opérateur qui remplace NULL par 0. Il est nécessaire pour les entreprises sans appels du tout.

Nos résultats :

Nous avons presque terminé. Le tableau ci-dessus présente la liste des entreprises, le nombre d'appels correspondant pour chacune d'entre elles, et la durée moyenne des appels dans chacune d'elles.

Il ne reste plus qu'à comparer les chiffres de la dernière colonne avec la durée moyenne de tous les appels de toutes les entreprises (335 secondes).

Si vous entrez la requête que nous avons présentée au tout début, ajoutez simplement le HAVING partie, vous obtiendrez ce dont vous avez besoin.

Nous vous recommandons fortement d'ajouter des commentaires sur chaque ligne afin que vous ne soyez pas confus à l'avenir lorsque vous devrez corriger certaines requêtes SQL complexes existantes.

Réflexions finales

Bien que chaque requête SQL complexe nécessite une approche individuelle, certaines recommandations conviennent à la préparation de la plupart de ces requêtes.

  • déterminer quelles tables participeront à la requête ;
  • créer des requêtes complexes à partir de parties plus simples ;
  • vérifier l'exactitude des requêtes de manière séquentielle, par parties ;
  • tester la précision de votre requête avec des tables plus petites ;
  • écrivez des commentaires détaillés sur chaque ligne contenant l'opérande, en utilisant les symboles '-'.

Des outils spécialisés rendent ce travail beaucoup plus simple. Parmi eux, nous vous recommandons d'utiliser le Query Builder - un outil visuel qui permet de construire même les requêtes les plus complexes beaucoup plus rapidement en mode visuel. Cet outil est disponible en tant que solution autonome ou dans le cadre de dbForge Studio multi-fonctions pour SQL Server.

Nous espérons que cet article vous a aidé à clarifier ce problème spécifique.