2010-10-14 8 views
5

Clause de non-responsabilité: Je suis un SQL newb et c'est pour une classe, mais je pourrais vraiment utiliser un poke dans la bonne direction.Limitations de GROUP BY

J'ai ces trois tables:

student(_sid_, sname, sex, age, year, gpa)
section(_dname_, _cno_, _sectno_, pname)
enroll(_sid_, grade, _dname_, _cno_, _sectno_)
(clés primaires dénotées par des underscores)

Je suis en train d'écrire une requête SQL compatible Oracle qui retourne une table avec le nom de l'étudiant (student.sname) qui a le plus haut gpa dans chaque section (y compris section.cno et section.sectno) ainsi que tous les autres attributs de section.

J'ai réussi à utiliser une requête globale et GROUP BY pour obtenir l'AMP maximale pour chaque section:

SELECT MAX(s.gpa), e.cno, e.sectno 
    FROM enroll e, 
     student s 
    WHERE s.sid = e.sid 
GROUP BY e.cno, e.sectno 

Sans parler des autres attributs section, je ne peux même pas comprendre comment virer de bord sur la nom de l'étudiant (student.sname). Si je l'ajoute à la clause SELECT, il doit être inclus dans GROUP BY qui gâche le reste de la requête. Si j'utilise cette requête entière à l'intérieur de la clause WHERE ou FROM d'une requête externe, je peux seulement accéder aux trois champs de la table, ce qui n'est pas très utile.

Je sais que vous ne pouvez pas me donner la réponse exacte, mais tous les conseils seraient appréciés!

+4

@OMG Poneys: J'aime la façon dont vous formatez les requêtes. – JoshD

+0

@JoshD: nous le faisons tous ;-) – zerkms

+0

Vous l'avez essentiellement dit. Ajoutez la table de section au FROM. Ajoutez des contraintes à la section WHERE to join pour vous inscrire. Ajoutez les colonnes que vous voulez voir au SELECT et répétez-les dans le GROUP BY. – kevpie

Répondre

3

En supposant Oracle 9i +, pour obtenir que l'un des étudiants les plus élevés GPA (en cas de liens) utiliser:

WITH summary AS (
    SELECT e.*, 
      s.name, 
      ROW_NUMBER() OVER(PARTITION BY e.cno, e.sectno 
           ORDER BY s.gpa DESC) AS rank 
    FROM ENROLL e 
    JOIN STUDENT s ON s.sid = e.sid) 
SELECT s.* 
    FROM summary s 
WHERE s.rank = 1 

équivalent non CTE:

SELECT s.* 
    FROM (SELECT e.*, 
       s.name, 
       ROW_NUMBER() OVER(PARTITION BY e.cno, e.sectno 
            ORDER BY s.gpa DESC) AS rank 
      FROM ENROLL e 
      JOIN STUDENT s ON s.sid = e.sid) s 
WHERE s.rank = 1 

Si vous voulez voir tous les étudiants qui ont fait l'égalité pour GPA, utilisez:

WITH summary AS (
    SELECT e.*, 
      s.name, 
      DENSE_RANK OVER(PARTITION BY e.cno, e.sectno 
           ORDER BY s.gpa DESC) AS rank 
    FROM ENROLL e 
    JOIN STUDENT s ON s.sid = e.sid) 
SELECT s.* 
    FROM summary s 
WHERE s.rank = 1 
1

Indice: Pensez qu'il peut y avoir plus d'un étudiant avec le GPA le plus élevé dans une classe. Une requête externe n'a besoin que des trois champs.

0

Peut-être la plus courte:

SELECT DISTINCT e.cno, e.sectno , e..., 
     FIRST_VALUE(s.sname) OVER 
           (PARTITION BY e.cno, e.sectno ORDER BY s.gpa DESC) 
FROM enroll e, 
    student s 
WHERE s.sid = e.sid 

Ou

SELECT A.* 
FROM 
    ( SELECT s._sid, s.sname, e.cno, e.sectno ,..., s.gpa 
       MAX(s.gpa) OVER (PARTITION BY e.cno, e.sectno) AS maxgpa 
     FROM enroll e, 
      student s 
     WHERE s.sid = e.sid 
    ) A 
WHERE A.maxgpa = A.gpa 
0

Voici quelques conseils: -

  1. Vous êtes sur la bonne voie avec votre groupe Par requête
  2. Cette fonction renvoie vous le GPA max pour chaque section basée sur les champs cno et sectno
  3. Maintenant, vous avez la valeur Max GPA pour chaque combinaison cno et sectno.
  4. Utilisez ces données de manière inversée si vous voulez maintenant trouver tous les élèves correspondant à ces valeurs de combinaison. TRUC: Examiner les résultats de votre groupe Par requête comme une table et utiliser un INNER JOIN
  5. Même s'il est possible qu'il y ait plus de 1 étudiants pour la même max GPA, vous aurez toujours les obtenir tous

Espérons que cela aide !!

0

Cela devrait vous donner ce que vous cherchez. Voir la fonction RANK() d'Oracle pour plus de détails sur la façon dont les GPA sont classées du plus haut au plus bas par section.

Exigences:

retour d'une table avec qui a le plus gpa le nom de l'étudiant (de student.sname) dans chaque section (section.cno et section.sectno), ainsi que tous les autres attributs de la section .

SELECT * FROM 
(
    SELECT 
     s.sname, 
     s.gpa, 
     sec.dname, 
     sec.cno, 
     sec.sectno, 
     sec.pname, 
     /* for each "sec.cno, sec.sectno", this will rank each GPA in order from highest to lowest. Ties will have the same rank. */ 
     RANK() OVER(PARTITION BY sec.cno, sec.sectno ORDER BY s.gpa DESC) as r_rank 
    FROM 
     enroll e, 
     student s, 
     section sec 
    WHERE 
     /* join enroll with student */ 
     s.sid = e.sid 
     /* join section with enroll */ 
     AND sec.dname = e.dname 
     AND sec.cno = e.cno 
     AND sec.sectno = e.sectno 
) 
WHERE r_rank = 1 /* this returns only the highest GPA (maybe multiple students) for each "sec.cno, sec.sectno" combination */ 
; 

Note: Si vous ne voulez pas les liens, le changement RANK() à ROW_NUMBER()