Ограничения GROUP BY - PullRequest
       17

Ограничения GROUP BY

5 голосов
/ 14 октября 2010

Отказ от ответственности : Я новичок в SQL, и это для класса, но я действительно мог бы использовать тыкать в правильном направлении.

У меня есть три таблицы:

student(_sid_, sname, sex, age, year, gpa)
section(_dname_, _cno_, _sectno_, pname)
enroll(_sid_, grade, _dname_, _cno_, _sectno_)
(первичные ключи обозначены подчеркиванием)

Я пытаюсь написать совместимый с Oracle SQL-запрос, который возвращает таблицу с именем учащегося (student.sname), которая имеет самый высокий gpa в каждом разделе (включая section.cno и section.sectno), а также все остальные атрибуты section.

Мне удалось использовать агрегированный запрос и GROUP BY, чтобы получить максимальный средний балл для каждого раздела:

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

Не говоря уже о других section атрибутах, я даже не могу понять, как привязать имя студента (student.sname). Если я добавлю его в предложение SELECT, оно должно быть включено в GROUP BY, что испортит остальную часть запроса. Если я использую весь этот запрос в предложении WHERE или FROM внешнего запроса, я смогу получить доступ только к трем полям таблицы, что не так уж и полезно.

Я знаю, что вы не можете дать мне точный ответ, но любые советы будут оценены!

Ответы [ 6 ]

3 голосов
/ 14 октября 2010

Предполагая Oracle 9i +, чтобы получить только одного из студентов с самым высоким средним баллом (в случае связей), используйте:

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

Не эквивалент 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

Вы хотите видеть всех студентов, которые связаны с GPA, используйте:

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 голос
/ 14 октября 2010

Подсказка: учтите, что в классе может быть более одного студента с самым высоким средним баллом.Внешний запрос требует только три поля.

0 голосов
/ 24 декабря 2013

Хотя на этот вопрос давным-давно ответили, но все же я хочу представить красивое объяснение , это очень полезно для новичка.Также Введение в SQL имеет такие правила.

0 голосов
/ 14 октября 2010

Это должно дать вам то, что вы ищете.См. Функцию Oracle RANK () для получения подробной информации о том, как GPA ранжируются от высшего к низшему по разделам.

Требования:

Возвращение таблицыс именем студента (student.sname), которое имеет самый высокий gpa в каждом разделе (section.cno и section.sectno), а также со всеми остальными атрибутами из раздела.

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

Примечание. Если вы это сделаетене хотите связей, измените RANK () на ROW_NUMBER ()

0 голосов
/ 14 октября 2010

Вот несколько указателей: -

  1. Вы находитесь на правильном пути с вашей группой По запросу
  2. Возвращает максимальный средний балл для каждого раздела на основе полей cno и sectno
  3. Теперь у вас есть значение Max GPA для каждой комбинации cno и sectno.
  4. Используйте эти данные, которые у вас есть, в обратном порядке, если вы хотите найти всех учеников, соответствующих этим комбинационным значениям. СОВЕТ: Рассмотрите результаты запроса Group By в виде таблицы и используйте INNER JOIN
  5. Даже если возможно, что для одного и того же максимального среднего балла более 1 студента, вы все равно получите их всех

Надеюсь, это поможет !!

0 голосов
/ 14 октября 2010

Возможно самое короткое:

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 

или

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
...