Обновление Oracle SQL Запрос в процедуре, но с ошибкой в ​​пропущенной правой скобке - PullRequest
0 голосов
/ 04 апреля 2020

Таблица sc содержит идентификатор студента и идентификатор курса, который они посетили, за которым следует соответствующий класс.

Таблица course содержит идентификатор курса и соответствующие кредиты

Таблица student1 содержит идентификатор студента и соответствующую информацию.

В этом случае мне нужно рассчитать средний балл каждого учащегося и добавить ранг в таблицу student1

Код следующий:

create or replace procedure save_scholarship is
begin
    UPDATE STUDENT1
       SET STUDENT1.gpa = (
              select rank() over (order by sum(sc.grade*course.credit)/sum(course.credit) desc)
                from sc
                   , course 
               where sc.sno = student1.sno
                 and sc.cno = course.cno 
                 and sc.sno not in (select sc.sno from sc where grade < 60) 
            group by sc.sno
            order by sum(sc.grade*course.credit)/sum(course.credit) desc
           )
         ;

end save_scholarship;

Это ошибка, которую я получил:

SQL Error: ORA-00907: missing right parenthesis

Ошибка находится на: порядок по сумме (с c .grade * course.credit) / сумма (course.credit) des c);

Кто-нибудь может мне помочь? Я новичок в Oracle 11g, в настоящее время изучаю его.

Я пытался запустить подзапрос обновления SQL, но он работал так, как ожидалось.

Просто не могу понять это вне.

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

Примечание. Я вполне уверен, что оптимизатор Oracle недостаточно наивен, чтобы генерировать подзапрос «ranked_students» ниже для каждой обновленной строки, но, конечно, всегда следует проверять свои оптимизации на значительных объемах данных. где это применимо, и используйте «объяснить план», чтобы решить, что лучше.

  • Мне кажется, что проблема с вашим запросом состоит в том, что функция rank () не производит функцию правильные результаты, потому что он смотрит только на одного студента за раз, и, следовательно, ранг этого студента всегда № 1 ... по отношению к себе!

  • Я также думаю, что вы, вероятно, хочу density_rank () в случае, если два студента имеют одинаковые средние баллы.

Итак, я сделал пример запроса, который использует предложение «with» для ранжирования всех студентов (у которых нет класс <60), а затем использует его для обновления таблицы student1. </p>

update student1
set student1.gpa = (
    with ranked_students as
    (
        select student1.sno,
            dense_rank() over (
                order by sum(sc.grade*course.credit)/sum(course.credit) desc
            ) as gpa
        from student1
        join sc on sc.sno = student1.sno
        join course on course.cno = sc.cno
        where not exists (
            select 1 from sc where sc.sno =student1.sno
            and sc.grade < 60
        )
        group by student1.sno
    )
    select gpa from ranked_students r
    where r.sno = student1.sno
);

select * from student1 order by gpa;

+-----+-------+-----+
| SNO | SNAME | GPA |
+-----+-------+-----+
| 002 | Alice | 1   |
| 001 | Bob   | 2   |
| 003 | Mary  |  -  |
+-----+-------+-----+

Вот инструкции для воссоздания моих таблиц тестирования:

create table sc as
select '001' as sno, 'C1' as cno, 80 as grade from dual
union select '001' as sno, 'C3' as cno, 70 as grade from dual
union select '002' as sno, 'C2' as cno, 90 as grade from dual
union select '003' as sno, 'C2' as cno, 59 as grade from dual
union select '003' as sno, 'C5' as cno, 98 as grade from dual;

create table student1 as
select '001' as sno, 'Bob' as sname, 100 as gpa from dual
union select '002' as sno, 'Alice' as sname, 100 as gpa from dual
union select '003' as sno, 'Mary' as sname, 100 as gpa from dual;

create table course as
select 'C1' as cno, 4 as credit from dual
union select 'C2' as cno, 4 as credit from dual
union select 'C3' as cno, 3 as credit from dual
union select 'C4' as cno, 3 as credit from dual
union select 'C5' as cno, 1 as credit from dual;

Приведенные выше таблицы описывают Алису a у нее высокий средний балл, у Боба - более низкий, а у Мэри - оценка ниже 60, что исключает ее из рейтинга.

Вот запрос, иллюстрирующий средние баллы среднего балла:

select student1.sno, student1.sname,
   round(sum(sc.grade*course.credit)/sum(course.credit),0) as gpa
from student1
join sc on sc.sno = student1.sno
join course on course.cno = sc.cno
group by student1.sno, student1.sname
order by gpa desc;

+-----+-------+-----+
| SNO | SNAME | GPA |
+-----+-------+-----+
| 002 | Alice |  90 |
| 001 | Bob   |  76 |
| 003 | Mary  |  67 |
+-----+-------+-----+
0 голосов
/ 04 апреля 2020

Используя ответ и схему @Jared, я думаю, что следующее слияние делает работу немного более эффективной:

merge into student1
using  (
        select student1.sno,
            dense_rank() over (
                order by sum(sc.grade*course.credit)/sum(course.credit) desc
            ) as gpa, min(grade) mgrade
        from student1
        join sc on sc.sno = student1.sno
        join course on course.cno = sc.cno
        group by student1.sno
    ) r
on (student1.sno=r.sno)
when matched then update set student1.gpa=case when mgrade<60 then null else r.gpa end;

И дополнение min (grade) может быть использовано и в его UPDATE. Преимущество слияния заключается в том, что расчет RANK выполняется один раз для всех строк.

...