2010-10-14 19 views
5

Disclaimer: Sono un newb SQL e questo è per una classe, ma potrei davvero usare un poke nella giusta direzione.Limitazioni di GROUP BY

ho queste tre tabelle:

student(_sid_, sname, sex, age, year, gpa)
section(_dname_, _cno_, _sectno_, pname)
enroll(_sid_, grade, _dname_, _cno_, _sectno_)
(chiavi primarie indicati con trattini)

Sto cercando di scrivere una query SQL compatibile con Oracle che restituisce una tabella con il nome dello studente (student.sname) con il valore gpa più alto in ogni sezione (compresi section.cno e section.sectno) e tutti gli altri attributi da section.

Sono riuscito a utilizzare una query di aggregazione e GROUP BY per ottenere il massimo GPA per ogni sezione:

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

Figuriamoci gli altri section attributi, non riesco nemmeno a capire come per virare sulla nome dello studente (student.sname). Se lo aggiungo alla clausola SELECT, deve essere incluso in GROUP BY, che compromette il resto della query. Se utilizzo questa intera query all'interno della clausola WHERE o FROM di una query esterna, posso accedere solo ai tre campi della tabella, che non sono molto utili.

So che non puoi darmi la risposta esatta, ma ogni suggerimento sarebbe apprezzato!

+4

@OMG Ponies: mi piace il modo in cui formatti le query. – JoshD

+0

@JoshD: lo facciamo tutti ;-) – zerkms

+0

L'hai praticamente detto. Aggiungi la tabella delle sezioni a FROM. Aggiungi vincoli alla sezione DOVE per partecipare alla registrazione. Aggiungi le colonne che desideri siano visibili a SELECT e ripeterle in GROUP BY. – kevpie

risposta

3

Supponendo Oracle 9i +, per ottenere solo uno degli studenti con il più alto GPA (in caso di parità) utilizzare:

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 

non CTE equivalente:

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 

Se si desidera vedere tutti gli studenti che hanno legato per GPA, utilizzare:

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

Suggerimento: considera che potrebbe esserci più di uno studente con il GPA più alto in una classe. Una query esterna richiede solo i tre campi.

0

Forse più breve:

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 

O

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

Ecco alcune indicazioni: -

  1. Siete sulla strada giusta con la vostra query GROUP BY
  2. Ciò restituisce il massimo GPA per ogni sezione in base ai campi cno e sectno
  3. Ora hai il valore Max GPA per ogni combinazione di cno e sectno.
  4. Utilizzare questi dati che si hanno in modo inverso se si desidera ora trovare tutti gli studenti che corrispondono a questi valori di combinazione. SUGGERIMENTO: Considerare i risultati della query GROUP BY come un tavolo e utilizzare un INNER JOIN
  5. anche se è possibile che ci sia più di 1 studenti per lo stesso massimo GPA, si continua a farli tutti

Spero che questo aiuti !!

0

Questo dovrebbe darvi quello che state cercando. Vedi la funzione Oracle RANK() per i dettagli su come i GPA sono classificati dal più alto al più basso per sezione.

Requisiti:

restituire una tabella con il nome dello studente (student.sname), che ha il più alto GPA in ogni sezione (section.cno e section.sectno), così come tutti gli altri attributi di sezione .

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 */ 
; 

Nota: se non si desidera cravatte, Cambio Posizione() per ROW_NUMBER()