MySQL ajoute le total de la colonne
-
20-08-2019 - |
Question
Je dois interroger cette base de données pour obtenir chaque ligne, mais également la somme de l'une des valeurs de colonne des résultats. Je pourrais utiliser php pour obtenir la valeur totale, mais il me faudrait alors exécuter deux boucles, une pour obtenir le total (qui se situe tout en haut des résultats). Je préférerais donc que la requête l’attrape et crée simplement un & Quot; total & Quot; row, mais le seul moyen de le faire fonctionner est avec une sous-requête qui est essentiellement une répétition de la requête d'origine. Y a-t-il un meilleur moyen?
SELECT
CONCAT(u.firstname, ' ', u.lastname ) name, u.id, s.description, s.shiftstart, s.shiftend,
(SELECT
SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600
FROM shifts
WHERE id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end') total
FROM shifts s
INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end'
ORDER BY shiftstart
Ce qui précède fonctionne et génère:
name id description shiftstart shiftend total
Joe User joeuser Stuff 2009-01-05 07:45:00 2009-01-05 12:15:00 39.5000
Joe User joeuser Stuff 2009-01-05 13:00:00 2009-01-05 17:00:00 39.5000
Joe User joeuser Stuff 2009-01-06 07:45:00 2009-01-06 10:45:00 39.5000
Joe User joeuser Stuff 2009-01-06 10:45:00 2009-01-06 12:45:00 39.5000
Joe User joeuser Stuff 2009-01-06 13:30:00 2009-01-06 14:30:00 39.5000
Joe User joeuser Stuff 2009-01-06 14:30:00 2009-01-06 17:00:00 39.5000
Joe User joeuser Stuff 2009-01-07 09:45:00 2009-01-07 14:00:00 39.5000
Joe User joeuser Stuff 2009-01-07 15:00:00 2009-01-07 17:00:00 39.5000
Joe User joeuser Stuff 2009-01-08 08:00:00 2009-01-08 12:15:00 39.5000
Joe User joeuser Stuff 2009-01-08 13:15:00 2009-01-08 17:00:00 39.5000
Joe User joeuser Stuff 2009-01-09 07:45:00 2009-01-09 10:45:00 39.5000
Joe User joeuser Stuff 2009-01-09 11:45:00 2009-01-09 15:15:00 39.5000
Joe User joeuser Stuff 2009-01-09 15:15:00 2009-01-09 17:00:00 39.5000
C'est ce dont j'ai besoin, mais ce n'est probablement pas la meilleure façon de l'obtenir.
La solution
MySQL prend en charge un modificateur spécial de regroupement par groupe appelé ROLLUP. .
SELECT CONCAT(u.firstname, ' ', u.lastname ) name, u.id,
s.description, s.shiftstart, s.shiftend,
SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600 total
FROM shifts s INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = ? AND DATE( shiftstart ) BETWEEN ? AND ?
GROUP BY u.id, s.shiftstart WITH ROLLUP
ORDER BY shiftstart;
Autres conseils
Le meilleur moyen est de faire cela avec du code. Les gens continuent d’insister sur l’utilisation de SQL, une algèbre relationnelle, pour s’acquitter de tâches procédurales. Essayer de mettre en place des procédures procédurales sur SQL est toujours une mauvaise idée, en termes de complexité et de performances. Suivez ces conseils d'un administrateur de base de données professionnel.
Exécutez deux requêtes à partir de votre code. Générez le plus grand ensemble en premier, puis la ligne totale dans le format de votre choix. Vos requêtes seront plus petites et plus simples, vos performances s'amélioreront et vous obtiendrez le résultat souhaité.
Autre conseil: l’espace disque est bon marché et la plupart des tables de base de données sont lues beaucoup plus souvent qu’elles ne sont écrites. Configurez un déclencheur d'insertion / mise à jour (si possible avec MySQL) pour renseigner une colonne distincte avec des champs calculés comme & Quot; CONCAT(u.firstname,' ',u.lastname)
& Quot; et l'utiliser pour les requêtes. Les fonctions par ligne ne sont pas évolutives et réduiront les performances de votre SGBD à mesure qu’il grandit.
Tout peut être meilleur par comparaison; la question est la comparaison avec quoi, non?
La question clé que vous avez indiquée est que vous vouliez que le total soit en haut des résultats. Crystal Reports et d'autres applications gèrent ce type de magie en tant que moteur 2 passes. Le premier passage obtient les totaux.
Il existe des compromis avec toute solution. Si vous obtenez un & Quot; total & Quot; séparé; rangée, l’application réceptrice devra alors la supprimer des résultats ou utiliser une autre astuce pour la masquer.
Une possibilité, qui peut être envisageable si vous n’écrivez pas pour un site Web à 1 million de visites / h, est tout simplement de faire 2 appels - un pour les informations de surcharge, telles que le nom, le temps TOTAL, etc. puis pour les détails ... Il apparaît dans la requête que vous sélectionnez les résultats d'une seule personne.
Nous sommes tous pour économiser les frais généraux et la bande passante, mais parfois, simple est mieux…
EDIT: Pax m'a battu au " save " bouton ... lol ...
Utilisez l'extension mysql fournie exactement à cette fin, comme décrit dans la réponse de Bill Karwin (que j'ai moi-même votée).
Si ce n'était pas disponible, l'option 2 serait une autre instruction SQL: SELECT SUM ...) SQL est vraiment optimisé pour être extrêmement efficace pour ce genre de choses, comparé à toute boucle de code procédural que vous êtes susceptible de faire écrire.