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.

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top