Roulement de Sommes dans SQL - un Exemple Pratique
Roulement de Sommes dans SQL - un Exemple Pratique
Date de publication : 05/08/2008
III. Observation intéressante l'utilisation de l'auto-jointure
III. Observation intéressante l'utilisation de l'auto-jointure


Qu'en est-il à propos de l'utilisation d'une variable utilisateur pour
faire le roulement de sommes depuis le début? Quelque chose de simple
comme ceci :
|
Damien a, bien sûr, raison sur le fait que j'aurais pu utiliser
une variable utilisateur comme ci-dessus pour générer le roulement
de sommes au lieu d'utiliser une auto-jointure.
Cependant, il y a quelques complications.
Premièrement, jetons un oeil à ce qu'il arrive si je ré-écris la requête originelle GROUP BY de Lenz afin d'y inclure une variable utilisateur pour calculer les totaux courants :
Premièrement, jetons un oeil à ce qu'il arrive si je ré-écris la requête originelle GROUP BY de Lenz afin d'y inclure une variable utilisateur pour calculer les totaux courants :
|
|
Comme vous pouvez le constater, nous avons quelques problèmes.
Clairement, la variable utilisateur @running_total n'est pas
calculée correctement quand elle est utilisée à la fois comme sortie
et comme affectation dans la même colonne. Observons maintenant ce qu'il
se passe si je sors la variable utilisateur d'affectation dans une colonne séparée...
|
Encore un coup de dé. Cepdenant, dans la sortie précédente, vous
pouvez voir plus clairement ce qui arrive à la requête :
le calcul du COUNT(*) est réalisé durant la phase du GROUP BY,
qui intervient après la sélection des lignes de données.
Malheureusement, le calcul d'une variable utilisateur d'affectation est réalisé pendant la phase de sélection des lignes, et depuis que l'affectation de @running_total à lui-même plus le groupement du COUNT(*) recquiert des informations non disponibles durant la phase de sélection des lignes, l'affectation n'est pas faite contrairement à nos attentes. Pour démontrer ceci plus loin, jetons un oeil à ce qui arrive si nous avons ajoutons un nombre constant, et non le résultat du COUNT(*) à la variable @running_total, dans une colonne séparée.
Malheureusement, le calcul d'une variable utilisateur d'affectation est réalisé pendant la phase de sélection des lignes, et depuis que l'affectation de @running_total à lui-même plus le groupement du COUNT(*) recquiert des informations non disponibles durant la phase de sélection des lignes, l'affectation n'est pas faite contrairement à nos attentes. Pour démontrer ceci plus loin, jetons un oeil à ce qui arrive si nous avons ajoutons un nombre constant, et non le résultat du COUNT(*) à la variable @running_total, dans une colonne séparée.
|
|
Comme vous pouvez le constater ci-dessus, ajouter une constante
à une variable utilisateur fonctionne comme voulu, résultant en
une incrémentation du total courant. Mais depuis que l'expression
COUNT(*) est évaluée pendant la phase GROUP BY,
l'affectation du total courant est faite par groupe, et par conséquent
ne correspond pas à nos attentes d'un total courant.
Donc, comment pouvons-nous sortir de cette impasse tout en utilisant
une variable utilisateur pour faire les sommes courantes?
Bien, nous pourrions revenir à notre vieille amie, la table dérivée, pour forcer le calcul du GROUP BY à être réalisé en premier, et ensuite appliquer la technique de Damien. Et, comme vous pouvez le constatez ci-dessous, ceci fonctionne très bien :
Bien, nous pourrions revenir à notre vieille amie, la table dérivée, pour forcer le calcul du GROUP BY à être réalisé en premier, et ensuite appliquer la technique de Damien. Et, comme vous pouvez le constatez ci-dessous, ceci fonctionne très bien :
|
|
Le fait que vous considérez l'exemple précédent comme plus simple ou plus
lisible que la technique de auto-joiture est entièrement de votre avis.
Les deux manière donnent des résultats identiques.
Eh! Mais qu'en est-il si je voulais une moyenne courante?
Mais, il y a plus d'une raison qui fait que je m'en tienne à la
technique de l'auto-jointure, et ceci pour les situations où
vous voulez plus qu'une somme courante, mais aussi si vous voulez
d'autres aggrégats courants. Un exemple courant serait si je voudrais
obtenir la moyennne courante des flux ajoutés à PlanetMySQL sur la durée
de vie de l'historique Planet. Utilisant une auto-jointure, le code
ressemble à ceci :
|
La requête SQL précédente ene une version légèrement modifiée des
totaux courants SQL avec une auto-jointure que j'ai démontrée dans
l'article d'hier. Les seuls changements sont que j'ai supprimé la clause
WHERE dans la sous-requête qui limite le jeu de données aux seuls
flux de 2007 et j'ai changé MONTH(created) par
DATE_FORMAT(created, '%Y-%m')
afin d'y inclure également l'année.

Notez qu'il n'y a pas que ce qui est cité précédemment qui change,
tout ce que j'avais à faire pour obtenir une moyenne courante avec la même
auto-jointure était d'ajouter cette ligne à la clause SELECT :
|
La fonction FLOOR() tronque simplement à partir du point décimal
de la moyenne et procède à un arrondi inférieur. Mais, il est tellement
simple d'ajouter un calcul de moyenne courante à ce bout de requête. Comment
aurions-nous procédé en utilisant les variables utilisateurs?
Bien, ça devient légèrement compliqué, puisque les moyennes se basent sur le nombre total d'objets étant moyennés, ce qui nécessite dans une variable utilisateur séparée. Voici comment procéder en utilisant les variables utilisateurs :
Bien, ça devient légèrement compliqué, puisque les moyennes se basent sur le nombre total d'objets étant moyennés, ce qui nécessite dans une variable utilisateur séparée. Voici comment procéder en utilisant les variables utilisateurs :
|
|
|
Comme vous pouvez le voir, il est possible d'obtenir des moyennes
courantes avec des variables utilisateurs, mais il s'agit d'une
délicate double affectation de variable utilisateur dans la colonne
de calcul de la colonne RunningAvg :
|
La première affectation est actuellement faite pour la variable
utilisateur @num_rows dans une parenthèse interne. La seconde
affectation (externe) est faite par la variable utilisateur @running_avg.
Nous devons faire cela car pour calculer la moyenne correctement,
nous avons besoin de diviser le total des flux ajoutés par le nombre de mois
(stockés dans la variable incrémentale @num_rows)...
Personnellement, pour des raisons telles que celles-ci, je préfère utiliser
la technique de l'auto-jointure car elle est plus lisible sur le long terme.
Dans un article à venir, je vais regarder un benchmark de performances pour
chaque méthode afin de voir s'il y a une différence notable...
Si vous désirez commenter cette article, Jay accepte les commentaire sur son blog,
http://jpipes.com.
