Quelle requête SQL faire ?

Pour récupérer des données à partir d’une base de données, le langage SQL est utile. Il permet de récupérer « d’un coup » les données souhaités en réalisant notamment des liens entre les différentes tables de données.

Nous allons voir rapidement comment construire une requête avec ce langage et quelle méthode utiliser pour certaines problématiques.

Pour illustrer les différentes problématiques, nous allons prendre l’exemple d’une base de données contenant les produits vendus et les prix des produits, ceci pour 2 enseignes du même groupe. Chaque enseigne est indépendante et a donc ses données dans des tables différentes, le lien entre les 2 enseignes se fait via l’identifiant des produits (qui est le même pour chaque produit dans les 2 enseignes).

La structure de la base de données peut être illustrée comme dans le schéma ci-dessous. Une base de données est un ensemble de tables. Chaque table contient des champs (les colonnes) et des lignes (les données). Ces tables sont liées entre elles avec des champs communs appelés des clés étrangères. Le schéma ci-dessous illustre les différentes tables avec les champs respectifs et les liaisons existantes.

La structure des requêtes SQL est souvent simple, mais cela peut vite se complexifier lorsque des tables ont des relations de 1 à N (par exemple 1 vente correspond à plusieurs produits achetés, et pas que 1 produit). Avant d’écrire une requête, il est donc conseillé de d’abord visualiser le schéma de la base de données (les types de liens entre tables) pour avoir le résultat souhaité.

Structure d’une requête SQL

Une requête SQL se fait en utilisant les termes suivants à chaque ligne. Chaque ligne correspond à une opération différente. L’ordre est relativement logique et correspond à peu près aux différentes étapes que suivra le moteur de la base de données.

SELECT + nom des champs/colonnes et calculs à faire (somme par exemple)

FROM + nom de la table où prendre les données

WHERE + conditions/filtres si nécessaires (ne prend en compte que les lignes de la table qui respectent la ou les conditions)

GROUP BY + nom des champs sur lesquels effectuer les regroupements pour les calculs (un tri décroissant est aussi réalisé en même temps)

HAVING + nom des champs pour faire un tri sur le résultat des regroupements (après les calculs)

Une requête SQL commence par une première ligne avec SELECT pour préciser les champs que l’on souhaite récupérer (l’ordre des champs/colonnes dans l’export sera déterminé par l’ordre précisé ici). Si on souhaite effectuer des calculs, comme une somme pour récupérer un total, le calcul doit être précisé ici (via la fonction sum(champ) pour faire une somme).

La deuxième ligne commence par FROM et précise la table dans laquelle on récupère les lignes (les données).

La troisième ligne commence par WHERE et correspond aux lignes que l’on souhaite récupérer dans la table. On précise donc ici les conditions (comme par exemple, les lignes où le 2ème champ est supérieur à 10). Il est possible de mettre plusieurs conditions avec AND ou OR selon que l’on souhaite une combinaison ou une union des conditions.

La quatrième ligne commence par GROUP BY et n’est utile que si on souhaite faire des calculs (comme une somme). Cette ligne va servir pour effectuer le calcul en fonction du regroupement précisé. Si on calcule une somme sans écrire cette ligne, le résultat ne contiendra qu’une seule ligne correspondant au total de toute la table. Alors que si on écrit cette ligne en précisant les champs concernés par le regroupement (par exemple, le deuxième champ), le résultat donnera donc le total pour chaque groupe (par exemple, le sous-total pour chaque valeur du deuxième champ).

La dernière ligne commence par HAVING et permet de réaliser le même type de filtres/conditions qu’avec WHERE. La seule différence est que le filtre se fait après les calculs avec HAVING, alors qu’avec WHERE le filtre se fait avant les calculs avec WHERE.

Nous allons faire un exemple de requête. La requête que nous souhaitons faire permet de connaitre le nombre de produit vendus par l’enseigne A. Il s’agit donc de la table « Ventes » dont on met ci-dessous le contenu.

Pour récupérer le nombre de ventes par produit, on ferait la requête suivante :

SELECT Produits, sum(nbVendus)

FROM Ventes

GROUP BY Produits

Et si on aurait souhaité avoir que les ventes par produit à partir du 01/01/2014, seulement pour les produits ayant fait 2 ventes ou plus, on ferait la requete suivante:

SELECT Produits, sum(nbVendus)

FROM Ventes

WHERE Date >= 20140101

GROUP BY Produits

HAVING sum(nbVendus) >=2

Comment faire une jointure entre 2 tables

La requête simple que nous avons vu ne portait que sur 1 seule table. Mais le plus souvent, les requêtes portent sur des informations qui sont dans différentes tables. Il faut donc utiliser les liaisons entre ces tables en réalisant ce qu’on appelle des jointures avec JOIN.

Nous allons voir le cas le plus fréquent de jointure qui est la jointure interne. Elle correspond à l’ajout d’information d’une table dans une autre table. Ainsi si on fait une jointure interne des 2 tables ci-dessous (A et B), on obtient la table C qui reprend la table A et ajoute pour chaque ligne les données correspondantes des colonnes de la table B.

La ligne de la jointure doit être placée après la ligne FROM. Et pour faire une jointure interne il faut préciser INNER JOIN avec la table à lier et les éléments permettant de faire la jointure. C’est à dire les champs communs dans les 2 tables et les champs pour lesquels il faut faire la liaison en commenceant par le terme ON (il est possible à ce niveau de faire un filtre pour ne conserver que les lignes qui correspondent à la règle fixée).

Ainsi, si on souhaite connaitre le chiffre d’affaire du 01/01/2014, nous avons besoin de lier la table « Ventes » qui contient les produits vendus avec la table « Produits » qui contient le prix des produits (ci-dessous). Pour cela, le champ commun est celui correspondant aux produits.

Ce qui donne la requête suivante (avec comme résultat 30) :

SELECT sum(Ventes.nbVendus*Produits.prix)

FROM Ventes

INNER JOIN Produits ON Produits.ProduitsID=Ventes.ProduitsId AND Ventes.Date=20140101

A noter qu’il est également possible de faire une jointure via la ligne WHERE. Mais la méthode avec JOIN permet de faciliter la lecture de la requête et elle offre plus de possibilités. Ci-dessous la même requête en passant par WHERE :

SELECT sum(Ventes.nbVendus*Produits.prix)

FROM Ventes, Produits

WHERE Produits.ProduitsID=Ventes.ProduitsId AND Ventes.Date=20140101

A quoi sert une jointure externe ?

Nous avons vu la jointure interne. Il existe d’autres types de jointures possibles selon la manière de réaliser la jointure. Nous allons voir le cas de la jointure externe.

Alors que la jointure interne ne conserve que les lignes de la première table et y ajoute les informations de la deuxième table, la jointure externe conserve les lignes des 2 tables, même si il n’y a pas de correspondances. Ce cas est utile pour prendre en compte toutes les informations, comme par exemple, avoir le chiffre d’affaire par produit même pour les produits qui n’ont pas fait de ventes (les produits qui ne sont donc pas dans la table ventes).

Pour réaliser une jointure externe, le terme à utiliser est OUTTER JOIN à la place d’INNER JOIN. L’utilisation est similaire à INNER JOIN en précisant la table à lier et les correspondances pour la jointure.

Ainsi, si on souhaite faire une jointure externe entre la table Ventes et la table Produits, la requête à faire est la suivante :

SELECT *

FROM VENTES as v

RIGHT OUTER JOIN Produits as p ON p.idProduits=v.Produits

Ce qui donne le résultat suivant où on observe que pour la dernière ligne, les 5 premières colonnes sont vides car il n’y a pas de correspondances (pas de ventes pour le produit 3).

Et si on souhaite avoir le détail du chiffre d’affaire par produit, même ceux qui n’ont fait aucune vente, cela donne :

select p.idProduits, sum(v.nbVendus*p.Prix) as CA

from VENTES as v

right outer join PRODUITS as p on p.idProduits=v.Produits

group by p.idProduits

L’image ci-dessous illustre tous les types de jointures possibles : INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTTER JOIN

A noter que lorsqu’il n’y a pas de correspondance entre les 2 tables, la jointure se fait en mettant la valeur NULL pour les champs où la jointure ne peut se faire. Ainsi pour réaliser des jointures spécifiques, où l’intersection des 2 tables n’est pas prise en compte, on réalise un filtre sur les lignes ayant la valeur NULL pour des champs. Il est également possible de mettre une aute valeur à la place de NULL, par exemple de mettre 0 en passant par la fonction IFNULL(champ,0).

Dans quel cas faire une union de tables ?

Nous avons vu comment faire une jointure entre tables, c’est à dire comment rajouter de nouveaux champs à une table via les informations d’une autre table. Mais si on a 2 tables avec les mêmes champs et qu’on souhaite les fusionner (ajouter les lignes de la deuxieme table en-dessous des lignes de la premiere), on ne pourra pas le faire via une jointure car il s’agit de ne rajouter que des lignes (et pas des champs/colonnes). Pour arriver à ce résultat, il faut faire ce qu’on appelle une union de table.

Le terme à utiliser est UNION. Il faut préciser les tables à unir en mettant une première avant UNION et la seconde après UNION. Et il faut s’assurer que dans les 2 tables, les champs/colonnes soient identiques et dans le même ordre.

Ci-dessous l’exemple d’union des tables Ventes (de l’enseigne A) et Ventes B (de l’enseigne B) pour avoir le nombre de ventes des 2 enseignes :

select *

from ventes

union

select *

from ventes B

Ci-dessous le résultat de l’union.

A noter qu’il est possible de rajouter un champ/colonne qui n’existe pas dans les tables. Le champ à créer est à mettre dans la ligne FROM en commenceant  par la valeur que doit contenir le champ (la valeur doit être précisée entre guillemets) et on précise l’intitulé du champ avec AS. Par exemple, pour distinguer les enseignes, un champ « Enseigne » pourrait être créée.

Comment faire des sous-requetes

Une sous-requête correspond à l’utilisation du résultat d’une requête pour faire une autre requête. Cette sous-requête peut être utilisé pour la ligne FROM, JOIN ou WHERE.

Une sous-requête s’écrit en ouvrant une parenthèse « ( » et se termine en fermant la parenthèse « ) », puis en donnant un nom à cette sous-requête avec « AS ».

Ci-dessous, on réalise une sous-requête pour avoir le total du chiffre d’affaire des 2 enseignes confondus. La sous-requête correspond à l’union des tables des 2 enseignes. Le résultat de cette sous-requête est ensuite utilisée pour calculer le total du chiffre d’affaire.

select sum(nbVendus*Prix) as CA

from

(

select *

from VENTES as v

inner join PRODUITS as p on v.Produits=p.idProduits

UNION

select *

from VENTES B as v2

inner join PRODUITS B as p2 on v2.Produits=p2.idProduits

) as t1

where idProduits='Produit 1'

Pour faciliter la lecture des requêtes, l’ouverture et la fermeture des parenthèses se fait sur une ligne à part. Et il est conseillé de mettre également des commentaires (les commentaires se font en commençant par #) pour préciser la ligne où commence la sous-requête et où elle est complètement finie. En effet, quand on ferme la parenthèse, ca ne correspond pas toujours à la fin de la sous-requête puisqu’il est possible de faire des jointures (JOIN), des filtres (WHERE) , des regoupements (GROUP BY), etc. La sous-requêtes se termine donc après toutes ces opérations. En procédant ainsi, il est plus facile de décortiquer la requête et de tester les sous-requête une par une.

A noter que le plus souvent, plutôt que de faire régulièrement une grande requête avec de multiples sous-requêtes, on préfère créer dans la base de données des tables de consolidation (qui enregistrent chaque nuit le résultat des sous-requetes). Ceci permet d’optimiser le travail du moteur de la base de données, en ne faisant le travail qu’une seule fois (le même principe qu’un cache). Cela évite ainsi d’avoir des requêtes trop gourmandes.

0.00 avg. rating (0% score) - 0 votes

Laissez un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *