1
votes

Moyenne calcule la moyenne pondérée dans SQL Server

Quelqu'un pourrait-il m'expliquer pourquoi la fonction AVG () me donne une moyenne pondérée dans mon code?

SELECT s.stud_id, s.country, SUM(e.paid) AS totalpaid
    INTO #totalpaid 
    FROM oc.students AS s
    JOIN oc.enrollment AS e ON s.stud_id = e.stud_id
GROUP BY s.country ,s.stud_id;

SELECT DISTINCT s.country, ROUND(AVG(t.totalpaid) OVER (PARTITION BY s.country),0) AS avg_country
    FROM #totalpaid t
    JOIN oc.students s ON t.stud_id = s.stud_id
    JOIN oc.enrollment e ON e.stud_id = s.stud_id; 

Par exemple, dans le cas de Malte Student12 a suivi 1 cours et a payé 45 EUR, Student837 a suivi 7 cours et payé 294 EUR au total. Je voudrais avoir un calcul simple (45 + 294) / 2 pour la moyenne mais le système calcule comme (1 * 45 + 7 * 294) / 8. Qu'est-ce que je fais mal? entrez la description de l'image ici


0 commentaires

4 Réponses :


2
votes

Parce que vous joignez deux fois vos tables.

En rassemblant les instructions INSERT et SELECT , votre requête équivaut à:

SELECT
  DISTINCT s.country, 
  ROUND(AVG(t.totalpaid) OVER (PARTITION BY s.country),0) AS avg_country
FROM (
  SELECT s.stud_id, s.country, SUM(e.paid) AS totalpaid
  FROM oc.students AS s
  JOIN oc.enrollment AS e ON s.stud_id = e.stud_id
  GROUP BY s.country ,s.stud_id    
) t
JOIN oc.students s ON t.stud_id = s.stud_id
JOIN oc.enrollment e ON e.stud_id = s.stud_id

Là, vous pouvez voir clairement le tableau étudiants et inscription sont rejoints deux fois. Cela produirait une fonction moyenne asymétrique.


1 commentaires

Je vois. Mais comment pourrais-je gérer le problème sans cela? Désolé si c'est très basique mais je ne vois pas l'autre sens. Pouvez-vous me donner un indice, s'il vous plaît?



2
votes

Dans votre deuxième requête, lorsque vous rejoignez votre table temporaire à l ' inscription , cela génère une ligne par classe; d'où proviennent les multiples valeurs de la colonne totalpaid .

La deuxième requête n'utilise pas de colonnes qui ne sont pas déjà dans la table temporaire, vous n'avez donc pas du tout besoin de ces jointures. Cela devrait produire ce que vous recherchez.

SELECT 
  t.country, 
  ROUND(AVG(t.totalpaid) OVER (PARTITION BY t.country),0) AS avg_country
FROM #totalpaid t
GROUP BY 
  t.country;


2 commentaires

Oui, vous avez tout à fait raison. Cependant le code que vous avez écrit me donne une erreur. Cela fonctionne: {SELECT DISTINCT t.country, ROUND (AVG (t.totalpaid) OVER (PARTITION BY t.country), 0) AS avg_country FROM #totalpaid t GROUP BY t.country, t.totalpaid;} Mais sans DISTINCT là sont à nouveau des valeurs multiples.


Ok en attendant je trouve la solution, j'ai totalement trop compliqué. Merci beaucoup.



1
votes
SELECT s.country, sum(e.paid) / count(DISTINCT s.stud_id) as average
FROM oc.students s 
JOIN oc.enrollment e ON e.stud_id = s.stud_id
GROUP BY s.country; 

1 commentaires

Les réponses de code uniquement ont tendance à être considérées comme de mauvaise qualité, à la fois pour l'utilisateur actuel qui pose la question et pour les futurs utilisateurs ayant des problèmes similaires. Une explication de votre solution ajoute une valeur significative à votre réponse.



1
votes

En attendant, j'ai trouvé la solution:

 SELECT
      country,
      ROUND(AVG(totalpaid) OVER (PARTITION BY country),0) AS avg_country
    FROM #totalpaid;

Super facile :)


0 commentaires