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?
4 Réponses :
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.
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?
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;
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.
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;
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.
En attendant, j'ai trouvé la solution:
SELECT
country,
ROUND(AVG(totalpaid) OVER (PARTITION BY country),0) AS avg_country
FROM #totalpaid;
Super facile :)