La Case de l’Oncle Tom

Développement Web, bonnes pratiques et performances

Utilisation de variables dans MySQL

MySQL, depuis la version 3.23.6, permet de déclarer des variables dans ses requêtes. Il est d’ailleurs possible de scripter ses requêtes mais c’est une autre histoire.

Ca peut sembler inutile à première vue lorsqu’on utilise MySQL au travers d’API d’autres langages (PHP, Perl, C# etc.). Et pourtant ça peut vous être très utile pour économiser des requêtes, du temps à programmer ces boucles et puis surtout, par flemme.

Oui, la flemme est pour moi la qualité numéro un du développeur car le flemmard a pour but d’arriver à ses fins en un minimum d’efforts.

Déclaration de variables

On peut déclarer une variable de deux façons dans MySQL.
La première méthode consiste à utiliser l’opérateur SET.

SET @pierre = 3, @feuille = 3 + 2, @ciseau = @pierre % @feuille ;

On peut également consister une variable à partir d’une requête.

SELECT @nb_total := COUNT(*) FROM `ma_table` ;

Note : dans ce cas là, on préfixe l’opérateur = de : (deux points).

Utilisation simple des variables

L’utilisation première qui peut en être faite c’est d’assainir vos requêtes SQL en évitant au maximum l’apparition de variables issues d’autres langages.
Avant :

SELECT * FROM `ma_table` WHERE colonne1 = {$variable1}, colonne2 = '{$variable2}' LIMIT 1;

Après :

SET @variable1 = {$variable1}, @variable2 = '{$variable2}';
SELECT * FROM `ma_table` WHERE colonne1 = @variable1, colonne2 = @variable2 LIMIT 1;

Comme les variables sont effectives pour la connexion courante, une variable MySQL peut être réutilisée à tout moment. De quoi décomplexifier certains scripts pas forcément bien structurés.

Utilisation complexe des variables

Les variables peuvent également être modifiées à même la requête. C’est à dire qu’à chaque itération effectuée par MySQL, le moteur va réévaluer le contenu de la variable. J’ai notamment eu besoin de ça pour ajouter de nouveaux éléments à la suite d’autres tout en renumérotant leur ordre. Je souhaitais éviter une boucle récursive en PHP qui aurait occasionné de multiples requêtes.

Je dispose d’une table (item_liste) avec plusieurs éléments, une clé primaire sur deux champs (item_id et item_cat) ainsi qu’un autre champ indexé permettant de les trier dans un ordre donné (item_ordre). Le but : prendre des éléments de la catégorie 1 pour les mettre à la suite de la catégorie 2.

Voici en gros ce que ça donne au final :

SELECT @ordre := IFNULL(MAX(item_ordre), 0) FROM `item_liste` WHERE item_cat = 2 ;

UPDATE `item_liste` SET item_ordre = @ordre := @ordre+1, item_cat = 2 WHERE item_cat = 1 ;
  1. On compte la borne supérieure de la catégorie 2. Pourquoi un IFNULL ? Parce MAX() retournera NULL si un des item_ordre en contient un. C’est une sécurité ;
  2. On met à jour les éléments de la catégorie 1 avec leur nouvel ordonnancement et leur nouvelle catégorie.

Alors pourquoi ça fonctionne ? La commande UPDATE balaie les lignes une par une et du coup, met à jour la variable @ordre à chaque ligne. Nous retrouvons ainsi l’effet désiré : incrémenter chaque ligne déplacée dans la nouvelle catégorie.

Il existe des utilisations plus compliquées que celles-là mais je pense que c’est un bon départ pour se faire une idée de ce qui est faisable par ce biais là. L’imagination et les besoins feront le reste ;-)

Votre version d'Adobe Flash Player n'est pas suffisamment à jour pour afficher cette animation.

Votre lecture de l'article Utilisation de variables dans MySQL est terminée. Il y a encore plein de choses à lire ici ... vous voulez des idées ?

Commentaires & rétroliens

  1. Capcaverne dit :

    j’ai rien compris : c’est qui qui gagne : la pierre, le ciseau la feuille ou le puit ?

  2. Oncle Tom dit :

    Le verre (de rouge) :P

  3. Super Chinois dit :

    Ces variables peuvent s’avérer très utiles, dans le cas où on a besoin de résultats intermédiaires etc …

    Merci du rappel ;-)

  4. gazza8 dit :

    Ca me semble n’avoir que pour seul inconvénient d’alourdir le code (en terme de nombre de lignes)…

    En tout cas, merci encore pour cette veille ’special dév’ utile et facile à comprendre :-)

  5. Oncle Tom dit :

    Je n’appellerais pas ça allourdir juste parce que ça rajoute une ou plusieurs lignes. Ca peut alléger la relecture des requêtes et simplifier les requêtes en elles-mêmes. L’exemple « complexe » cité aurait tenu sur davantage de lignes. Ca c’est de l’allourdissement.

    De toutes façons, quand on s’appête à écrire une usine à gaz pour un problème simple en apparence, il y a (presque) toujours une solution nous simplifiant la vie qui n’attend qu’à être découverte / utilisée.

  6. Chouchou dit :

    C’est bien, avoir ton blog dans ses favoris, et en lisant ce genre d’article, on se croit plus intelligent :)

  7. Je cherche « variable mysql » dans google.
    Pif en troisième résultat je vois ton blog juste derrière la doc officielle. Paf, je clique, je consulte tes exemples, je l’applique à mon besoin et pouf mon problème est résolu.
    Que dire? Merci OncleTom tout simplement! ;)

  8. Francis33 dit :

    Bonjour,

    Je suis en train d’apprendre à utiliser les requêtes dans Mysql.
    J’ai une série assez complexe à utiliser, avec des UNION sur des SELECT, ce qui fait que la requête finale augmente en taille d’une façon impressionnante.
    Pour améliorer la visibilité et la compréhension d’une requête complexe, je voudrais savoir s’il est possible de définir une variable égale à une table obtenue comme résultat d’une requête.
    Par exemple si j’ai un SELECT…UNION …, comment faut-il déclarer la variable, si c’est possible ?

    merci

    • Oncle Tom dit :

      Faudrait que tu regardes du côté des vues et des procédures stockées (scripting avancé de requêtes avec des logiques de programmation).

      Il faut surtout se focaliser sur les performances et les index utilisés plus que par la longueur même de la requête.

Répondre

Balises HTML autorisées : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Thème graphique par LeslyG, intégré par Oncle Tom.
Propulsé par WordPress, Blueprint et WP-LESS.