ApplePie
ApplePie

Reputation: 8942

MS Access SQL Query using Sum() and Count() gives incorrect results

I am having an issue with a query which returns results that are very far from reality (not only does it not make sense at all but I can also calculate the correct answer using filters).

I am building a KPI db for work and this query returns KPIs by employee by period. I have a very similar query from which this one is derived which returns KPIs by sector by period which gives the exact results I have calculated using a spreadsheet. I really have no idea what happens here. Basically, I want to sum a few measures that are in the maintenances table like temps_requete_min, temps_analyse_min, temps_maj_min and temps_rap_min and then create a subtotal AND present these measures as hours (measures are presented in minutes, thus the divide by 60).

SELECT 
    [anal].[prenom] & " " & [anal].[nom] AS Analyste, 
    maint.periode, maint.annee, 
    Round(Sum(maint.temps_requete_min)/60,2) AS REQ, 
    Round(Sum(maint.temps_analyse_min)/60,2) AS ANA, 
    Round(Sum(maint.temps_maj_min)/60,2) AS MAJ, 
    Round(Sum(maint.temps_rap_min)/60,2) AS RAP,       
    Round((Sum(maint.temps_requete_min)+Sum(maint.temps_analyse_min)+Sum(maint.temps_maj_min)+Sum(maint.temps_rap_min))/60,2) AS STOTAL, 
    Count(maint.periode) AS Nombre, 
    a.description

FROM 
    rapports AS rap, 
    analyste AS anal, 
    maintenances AS maint, 
    per_annuelle, 
    annees AS a

WHERE 
    (((rap.id_anal_maint)=anal.id_analyste) And
    ((maint.id_fichier)=rap.id_rapport) And 
    ((maint.maint_effectuee)=True) And 
    ((maint.annee)=per_annuelle.annee) And
    ((per_annuelle.annee)=a.annees))

GROUP BY 
    [anal].[prenom] & " " & [anal].[nom], 
    maint.periode, 
    maint.annee, 
    a.description, 
    anal.id_analyste

ORDER BY 
    maint.annee, maint.periode;

All measures are many orders of magnitude higher than what they should be. I suspect that my Count() is wrong, but I can't see what would be wrong with the sums :|

Edit: Finally I have come up with this query which shows the same measures I have calculated using Excel from the advice given in the comments and the answer provided. Many thanks to everyone. What I would like to know however, is why it makes a difference to use explicit joins rather than implicit joins (WHERE clause on PKs).

SELECT
    maintenances.periode,
    [analyste].[prenom] & " " & analyste.nom,
    Round(Sum(maintenances.temps_requete_min)/60,2) AS REQ,
    Round(Sum(maintenances.temps_analyse_min)/60,2) AS ANA, 
    Round(Sum(maintenances.temps_maj_min)/60,2) AS MAJ, 
    Round(Sum(maintenances.temps_rap_min)/60,2) AS RAP,
    Round((Sum(maintenances.temps_requete_min)+Sum(maintenances.temps_analyse_min)+Sum(maintenances.temps_maj_min)+Sum(maintenances.temps_rap_min))/60,2) AS STOTAL, 
    Count(maintenances.periode) AS Nombre

FROM 
    (maintenances INNER JOIN rapports ON maintenances.id_fichier = rapports.id_rapport)
    INNER JOIN analyste ON rapports.id_anal_maint = analyste.id_analyste

GROUP BY analyste.prenom, maintenances.periode

Upvotes: 2

Views: 5402

Answers (1)

Gordon Linoff
Gordon Linoff

Reputation: 1269773

In this case, the problem is typically that your joins are bringing together multiple dimensions. You end up doing a cross product across two or more categories.

The fix is to do the summaries independently along each dimension. That means that the "from" clause contains subqueries with group bys, and these are then joined together. The group by would disappear from the outer query.

This would suggest having a subquery such as:

from (select maint.periode, maint.annee,
             Round(Sum(maint.temps_requete_min)/60,2) AS REQ, 
             Round(Sum(maint.temps_analyse_min)/60,2) AS ANA, 
             Round(Sum(maint.temps_maj_min)/60,2) AS MAJ, 
             Round(Sum(maint.temps_rap_min)/60,2) AS RAP,       
             Round((Sum(maint.temps_requete_min)+Sum(maint.temps_analyse_min) +Sum(maint.temps_maj_min)+Sum(maint.temps_rap_min))/60,2) AS STOTAL, 
             Count(maint.periode) AS Nombre, 
      from maintenances maint
      group by maint.periode, maint.annee
     ) m

I say "such as" because without a layout of the tables, it is difficult to see exactly where the problem is and what the exact solution is.

Upvotes: 3

Related Questions