Ludovic ROLAND

Blog technique sur mes expériences de développeur.

Interagir avec une base de données en Perl 5 grâce au module DBI (4/7) : Les requêtes de sélection

6 août 2022

Nous allons voir par la suite qu’il n’existe pas qu’une seule façon d’exécuter des requêtes en Perl.

Puisqu’il faut bien choisir, je vous propose de commencer par les requêtes de sélection.

Pas de panique, les autres types de requêtes seront vus dans les chapitres qui suivent. ;)

Plan

Création d’une requête pas à pas

Prenons un exemple. Je vous propose de travailler sur la requête suivante :

SELECT * FROM MARQUE

Préparer sa requête

Avant d’exécuter la requête, nous devons la préparer. Pour ça, nous allons utiliser la fonction prepare() de notre descripteur de base en lui précisant notre requête en tant que paramètre.

Pour préparer les requêtes, on retrouve généralement 2 types de syntaxe. Soit en un étape, soit en 2 étapes. Voici tout de suite un exemple :

#Syntaxe en 1 ligne
my $prep = $dbd->prepare('SELECT * FROM MARQUE');

#Syntaxe en 2 lignes
my $requete = 'SELECT * FROM MARQUE';
my $prep = $dbd->prepare($requete);

Ici, je viens donc de préparer la requête me permettant de sélectionner tous les champs de la table MARQUE de notre base de données.

Jusqu’ici, il n’y a rien de bien compliqué, cependant, il ne faut pas confondre les notions de préparation de d’exécution. Ici, nous préparons notre requête à être exécuter, mais nous ne pouvons en aucun cas en extraire un quelconque résultat.

Vous pouvez constater l’apparition d’une nouvelle variable : $prep. C’est cette variable que l’on utilisera dans la suite de notre programme pour exécuter notre requête et en exploiter les résultats.

Sachez également qu’il est une nouvelle fois possible de gérer d’éventuelles exceptions grâce aux mots-clefs or die.

Voici d’ailleurs un exemple de syntaxe :

my $requete = 'SELECT * FROM MARQUE';
my $prep = $dbd->prepare($requete)
    or die 'Impossible de préparer la requête : '.$dbd->errstr;

Le fait de concaténer notre message d’erreur à la valeur retourner par la méthode errstr de notre descripteur de base nous permet de connaître avec précision l’origine du dysfonctionnement.

Exécuter la requête

Maintenant que notre requête est préparée, nous allons pouvoir passer à son exécution. Pour ça, nous allons utiliser la méthode execute à partir de la variable qui contient notre requête préparée.

Puisqu’un exemple est souvent plus parlant, je vous propose un :

$prep->execute;

Comme à chaque fois, il est possible de gérer les éventuelles exceptions :

$prep->execute
    or die 'Impossible d\'exécuter la requête : '.$prep->errstr;

Terminer sa requête

Sans forcément rentrer dans les détails, il faut que vous sachiez qu’une exécution de requête prend de la place dans la mémoire de votre ordinateur. Il est donc nécessaire, lorsqu’on ne souhaite plus utiliser les résultats de la requête, de libérer cette mémoire réservée.

Pour ça, nous allons utiliser la fonction finish.

Voici comment procéder :

$prep->finish;

Pour résumer

Afin de résumer ce que nous venons de voir au cours de ce chapitre, je propose de voir le code complet :

#!/usr/bin/perl

use strict;
use DBI;

my $base    =   'Zvoitures';
my $hote    =   '127.0.0.1';
my $login   =   'root';
my $mdp     =   '';

my $dbd = DBI->connect( "dbi:mysql:dbname=$base;host=$hote;",$login, $mdp)
    or die 'Connexion impossible à la base de données : '.DBI::errstr;

my $requete = 'SELECT * FROM MARQUE';

my $prep = $dbd->prepare($requete)
    or die 'Impossible de préparer la requête : '.$dbd->errstr;

$prep->execute
    or die 'Impossible d\'exécuter la requête : '.$prep->errstr;

$prep->finish;

$dbd->disconnect;

N’oubliez jamais que vous utilisez Perl, et qu’il est toujours possible d’utiliser des marqueurs. Ainsi, il est tout à fait possible d’écrire vos requêtes sous la forme d’un bloc comme il est de convention d’écriture dans la plupart des SGBD :

my $requete = <<"SQL";
    SELECT *
    FROM MARQUE
SQL

Cette écriture sera d’autant plus lisible lorsque vous aurez besoin d’écrire de grosses requêtes avec tout un tas de jointures.

Exploiter le résultat

Maintenant que nous venons de voir comment faire une requête, je vous propose de voir comment exploiter les résultats renvoyés.

Exploiter les résultats Nous allons voir ici 2 cas, ce qui nous permettra de rencontrer et manipuler différentes fonctions.

  • Cas n°1 : il s’agit du cas où vous connaissez le nombre d’arguments.
  • Cas n°2 : il s’agit du cas où vous ne connaissez pas le nombre d’arguments.

Cas n°1

Reprenons la requête précédente :

SELECT * FROM MARQUE

Puisque nous connaissons la structure de notre table de données, nous pouvons transformer notre requête afin d’en détailler les différents champs que nous voulons sélectionner.

Voici ce que ça donne :

SELECT numMarque, nomMarque FROM MARQUE

Si vous n’êtes pas convaincus que ces 2 requêtes sont équivalentes, je vous invite à les exécuter dans votre SGBD. ;)

Il existe une multitude de manières d’exploiter les données renvoyées par une requête SQL. Je vous propose de voir la méthode la plus courante.

Puisque bien souvent un bout de code vaut mieux que de longues explications, voici tout de suite comment faire :

while (my($numMarque, $nomMarque) = $prep->fetchrow_array ) {
    print $numMarque . '. ' . $nomMarque . "\n";
}

Quelques explications : La méthode execute renvoie un tableau qui contient toutes les lignes qui ont été sélectionnées par notre requête. La méthode fetchrow_array est une fonction qui renvoie une ligne de ce fameux tableau. C’est d’ailleurs parce que cette fonction nous renvoie un tableau que nous pouvons utiliser une liste pour recueillir nos résultats.

La boucle while quant à elle, nous permet de réaliser une boucle sur les lignes du tableau contenant les résultats et ainsi, d’exploiter toutes les lignes et donc tous les résultats sans en oublier.

Si l’on reprend le script précédent, ces 3 lignes se placent juste avant l’instruction $prep->finish.

Voici tout de suite l’affichage produit par ce script :

> perl requete.pl
1. ZeroMobile
2. Renault
3. Peugeot
4. Ferrari
5. Porsche
6. Fiat
7. Ford
8. Tata Motor
9. Smart
10. Citroen

Cas n°2

Pour rappel, il s’agit du cas où nous ne connaissons pas le nombre d’arguments.

Reprenons donc notre requête sous sa première forme :

SELECT * FROM MARQUE

Dans ce second cas, utiliser une liste pour recueillir les résultats n’a pas de sens, puisque nous ne connaissons pas le nombre de champs renvoyés. Il conviendra alors d’utiliser un tableau.

Bien sûr, l’exploitation sera différente du premier cas. Afin d’afficher les résultats, nous allons être obligés d’utiliser une nouvelle boucle : la boucle foreach. Nous allons donc imbriquer 2 boucles afin d’exploiter les résultats de notre requête.

Voyons tout de suite comment faire :

while (my @data = $prep->fetchrow_array ) {
    foreach my $elt (@data) {
        print $elt.' ';
    }
    print "\n";
}

En exécutant ce script dans votre terminal, vous devriez alors avoir :

> perl requete.pl
1 ZeroMobile 
2 Renault 
3 Peugeot 
4 Ferrari 
5 Porsche 
6 Fiat 
7 Ford 
8 Tata Motor 
9 Smart 
10 Citroen

Cette méthode peut se révéler intéressante dans le cas d’une requête SQL ayant énormément de champs dans le SELECT afin de rendre le code de votre script plus clair.

Compter le nombre de lignes renvoyées

Vous avez 10 minutes pour y réfléchir ! :p

Tic… Tac… Tic… Tac…

Voyons ensemble les 3 réponses qui reviennent le plus souvent.

  • Incrémenter une variable dans la boucle while.
  • Faire une autre requête avec un COUNT(*).
  • Utiliser une fonction que tu vas nous révéler.

L’idée du compteur à incrémenter dans la boucle while n’est pas une mauvaise idée, mais la bonne réponse est bien évidemment la dernière !

En effet, il existe une fonction qui permet de connaître le nombre de lignes retournées par notre requête. La voici sans plus attendre :

$prep->rows

Ainsi, si on ajoute cette ligne à notre script :

print 'Il existe '.$prep->rows.' marques de voitures.';

Nous allons obtenir à l’écran :

Il existe 10 marques de voitures.

Le script complet

Comme à chaque fois en fin de chapitre, voici le script complet de ce que nous avons vu :

#!/usr/bin/perl

use strict;
use DBI;

my $base    =   'Zvoitures';
my $hote    =   '127.0.0.1';
my $login   =   'root';
my $mdp     =   '';

my $dbd = DBI->connect("dbi:mysql:dbname=$base;host=$hote;",$login, $mdp)
    or die 'Connexion impossible à la base de données : '.DBI::errstr;

my $requete = 'SELECT * FROM MARQUE';

my $prep = $dbd->prepare($requete)
    or die 'Impossible de préparer la requête : '.$dbd->errstr;

$prep->execute
    or die 'Impossible d\'exécuter la requête : '.$prep->errstr;

while (my($numMarque, $nomMarque) = $prep->fetchrow_array ) {
    print $numMarque.'. '.$nomMarque."\n";
}

print 'Il existe '.$prep->rows.' marques de voitures.';

$prep->finish;

$dbd->disconnect;

Vous avez acquis un certain nombre de connaissances, c’est pourquoi je vous propose d’ores et déjà un petit TP !

Commentaires