PL / SQL: Как отобразить название темы и имена лекторов в процедуре? - PullRequest
0 голосов
/ 01 июня 2018

В моей процедуре в качестве параметра будет выбран код субъекта, а затем будет отображаться название темы и имена лекторов, которые преподавали этот предмет до 2016 года. Моя процедура также должна предложить ввести код субъекта и отобразить результаты.Я попробовал свой код следующим образом, не помещая его в процедуру, и он возвращает правильные результаты, но когда я включаю свой код как часть процедуры PL / SQL, я получаю сообщение об ошибке

Предупреждение:Процедура создана с ошибками компиляции.

Я совершенно новичок в PL / SQL, поэтому любые советы будут полезны!Код процедуры, который я пробовал в течение нескольких часов, выглядит следующим образом:

    CREATE OR REPLACE PROCEDURE WHO(CODE CHAR)
IS
FNAME VARCHAR(256)
LNAME VARCHAR(256)
TITLE VARCHAR(256)

CURSOR C1
IS
    SELECT FIRST_NAME, LAST_NAME, SUBJECT.NAME
    FROM ACADEMIC INNER JOIN TEACHES
    ON STAFF# = LECTURER
    INNER JOIN SUBJECT
    ON TEACHES.CODE=SUBJECT.CODE
    WHERE YEAR<2016 AND TEACHES.CODE=CODE
    GROUP BY FIRST_NAME, LAST_NAME, SUBJECT.NAME;
BEGIN
    OPEN C1;
    LOOP
    IF C1%NOTFOUND THEN EXIT;
    END IF;
    FNAME=FIRST_NAME;
    LNAME=LAST_NAME;
    DBMS.OUTPUT.PUT_LINE(FNAME||' '||LNAME);
    TITLE=SUBJECT.NAME;
    DBMS.OUTPUT.PUT_LINE(TITLE);
    END LOOP;
    CLOSE C1;
END WHO;
/

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Вы идете в правильном направлении, но есть несколько опечаток ..

Но к вашему основному вопросу:

Вы должны FETCH строк в переменных.Вот пример.

DECLARE
    FNAME   VARCHAR (256); -- you need some semicolons here ;)
    LNAME   VARCHAR (256);
    NAME    VARCHAR (256);
    TITLE   VARCHAR (256);

    CURSOR C1 -- replaced you query with a dummy-query. Yours should also work
    IS
        SELECT 'Hans' FIRST_NAME, 'Schnitzel' LAST_NAME, 'The Schnitzel' NAME
          FROM DUAL
        UNION ALL
        SELECT 'Heinrich' FIRST_NAME, 'Wurst' LAST_NAME, 'The Sausage' NAME
          FROM DUAL;
BEGIN
    OPEN C1; -- open cursor

    LOOP
        FETCH C1 INTO FNAME, LNAME, NAME; -- try to read the row and put the values into our variables

        IF C1%NOTFOUND -- check if we got a row
        THEN
            EXIT;
        END IF;

        DBMS_OUTPUT.put_line ('Name: ' || FNAME || ' ' || LNAME); -- work with is.
        TITLE := NAME;
        DBMS_OUTPUT.put_line ('Title: ' || TITLE);
    END LOOP;

    CLOSE C1;
END;
0 голосов
/ 01 июня 2018

Такие инструменты, как SQL Developer, PL / SQL Developer и т. Д., Будут выделять ошибки компиляции, или в командной строке SQL * Plus вы можете ввести

show errors

сразу после компиляции, или же

show errors procedure who

Или вы можете запросить таблицу user_errors.Какой бы инструмент вы ни использовали, вы должны уметь работать с ошибками компиляции.

Начните с того, чтобы привести в порядок код, чтобы его было легче читать и выполнять, и в целом он выглядит более профессионально.Кроме того, хотя они на самом деле не вызывают каких-либо ошибок, вы должны действительно изменить эти типы char и varchar на стандартные varchar2 (в идеале все должно быть привязано как academic.first_name%type и т. Д., Но по одному за раз).

Вот исправленная версия:

create or replace procedure who
    ( code subject.code%type )  -- CHAR is a disastrous datatype you should never need
is
    fname varchar2(50);  -- VARCHAR2 is the standard string type, VARCHAR is reserved
    lname varchar2(50);  -- Also PL/SQL requires terminating semicolons here
    title varchar2(256);

    cursor c1 is
        select first_name
             , last_name
             , subject.name
        from   academic
               join teaches
                    on  staff# = lecturer
               join subject
                    on  teaches.code = subject.code
        where  year < 2016
        and    teaches.code = who.code  -- "code" on its own is ambiguous
        group by first_name, last_name, subject.name;

begin
    open c1;
    loop
        fetch c1 into fname, lname, title;  -- Added 'fetch into'

        if c1%notfound then
            exit;
        end if;

        dbms_output.put_line(fname || ' ' || lname);  -- It's dbms_output, with a '_'
        dbms_output.put_line(title);
    end loop;

    close c1;
end who;

Компилируется.Но вы все еще можете упростить это, используя Cursor FOR Loop вместо сложного, многословного способа:

create or replace procedure who
    ( code subject.code%type )
is
begin
    for r in (
        select first_name
             , last_name
             , subject.name as title
        from   academic
               join teaches
                    on  staff# = lecturer
               join subject
                    on  teaches.code = subject.code
        where  year < 2016
        and    teaches.code = who.code
        group by first_name, last_name, subject.name
    )
    loop
        dbms_output.put_line(r.first_name || ' ' || r.last_name);
        dbms_output.put_line(r.title);
    end loop;
end who;

Это неявно объявляет курсор и запись с именем r с тремяполя, основанные на курсоре, и он обрабатывает открытие, выборку и закрытие для вас.

Я не знаю ваших таблиц, но я предполагаю, что они примерно такие:

create table subject
( code        varchar2(20) primary key
, name        varchar2(30) not null );

create table academic
( staff#      integer primary key
, first_name  varchar2(20) not null
, last_name   varchar2(20) not null );

create table teaches
( lecturer    references academic(staff#) not null
, code        references subject not null
, year        number(4,0) not null
, constraint teaches_pk primary key (lecturer, code, year) );

Если это так, я бы использовал псевдонимы таблиц в запросе, как показано ниже, чтобы избежать двусмысленности:

select a.first_name
     , a.last_name
     , s.name as title
from   academic a
       join teaches t
            on  t.lecturer = a.staff#
       join subject s
            on  s.code = t.code
where  t.year < 2016
and    t.code = who.code
group by a.first_name, a.last_name, s.name
0 голосов
/ 01 июня 2018

У вас мало проблем с вашим кодом.Некоторые пропущенные полуколоны при декалировании.См. Ниже:

CREATE OR REPLACE PROCEDURE WHO( CODE CHAR)
IS
  FNAME VARCHAR(256); --<Missing Semicolon
  LNAME VARCHAR(256); --<Missing Semicolon
  TITLE VARCHAR(256); --<Missing Semicolon

  CURSOR C1
  IS
    SELECT FIRST_NAME,
      LAST_NAME,
      SUBJECT.NAME
    FROM ACADEMIC
    INNER JOIN TEACHES
    ON STAFF# = LECTURER
    INNER JOIN SUBJECT
    ON TEACHES.CODE =SUBJECT.CODE
    WHERE YEAR      <2016
    AND TEACHES.CODE=CODE
    GROUP BY FIRST_NAME,
      LAST_NAME,
      SUBJECT.NAME;
BEGIN
  OPEN C1;
  LOOP    
    --this is how you put the value of cursor to variable
    FETCH C1 into FNAME ,LNAME ,TITLE ;

    --No need for IF to exit loop. You can use as shown below
    EXIT when C1%NOTFOUND;    

    DBMS_OUTPUT.PUT_LINE(FNAME||' '||LNAME);
    DBMS_OUTPUT.PUT_LINT(TITLE);
  END LOOP;
  CLOSE C1;
END WHO;
/

Демо:

CREATE OR REPLACE PROCEDURE WHO( CODE CHAR)
IS  
  FNAME number;  
  CURSOR C1
  IS
    SELECT contract_id FROM TX;

BEGIN
  OPEN C1;
  LOOP    
    fetch c1 into FNAME;
    EXIT when C1%NOTFOUND;    

    DBMS_OUTPUT.PUT_LINE(FNAME);

  END LOOP;
  CLOSE C1;
END WHO;
/

Выход:

1
1
1
2
2
2
3
3
...