【问题标题】:PL/SQL : How to display subject title and lecturer names in a procedure?PL/SQL:如何在程序中显示主题名称和讲师姓名?
【发布时间】:2018-11-11 05:12:44
【问题描述】:

我的程序会接受一个学科代码作为参数,然后继续显示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;
/

【问题讨论】:

  • 我将不得不显示主题名称,不幸的是它被放置在另一个名为主题的表中。还有其他方法吗?
  • 你能把 DBMS_OUTPUT.PUT_LINT 改成 DBMS_OUTPUT.PUT_LINE
  • 抱歉打错了。我试过但仍然是同样的错误:(
  • 你用什么工具来开发PL/SQL?您需要了解如何使用它来查看编译错误,即使它只是查询user_errors。 SQL Developer 等将以交互方式突出显示它们。 SQL*Plus 有show errors 命令等
  • 不是您的编译错误,而是teaches.code = code 应该是teaches.code = who.code(或者使用行业标准的参数命名约定,例如p_code)。

标签: sql database oracle plsql procedure


【解决方案1】:

您的代码几乎没有问题。 decalation 时缺少一些分号。见下文:

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

【讨论】:

  • :'( 你更快。也许添加一个变量赋值:= 他也有那些错别字..
  • 感谢您对错别字的建议!但遗憾的是我仍然遇到同样的错误:(
  • @WendyChong 你在说什么错误。请参阅正在运行的演示。检查您的查询是否正确。
【解决方案2】:

你的方向是正确的,但是有一堆错别字..

但是对于你的主要问题:

您必须将行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;

【讨论】:

  • 感谢您对错别字的建议!但遗憾的是我仍然遇到同样的错误:(
  • 你运行的是什么版本?哪一行有错误?你能运行我的例子吗?
【解决方案3】:

SQL Developer、PL/SQL Developer 等工具会高亮显示编译错误,或者在 SQL*Plus 命令行中输入

show errors

编译后立即,否则

show errors procedure who

或者您可以查询user_errors 表。无论您使用什么工具,您都需要能够处理编译错误。

首先整理代码,使其更易于阅读和遵循,并且通常看起来更专业。此外,尽管它们实际上并没有导致任何错误,但您应该真正将这些 charvarchar 类型更改为标准 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

【讨论】:

  • 非常感谢!我设法调试了我遇到的错误,您提供的额外建议真的很有帮助!对不起,如果我没有专业地格式化它,因为我刚刚学习了 PL/SQL。感谢您成为我的救星!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-09
  • 1970-01-01
  • 2018-05-05
  • 2014-01-25
  • 2010-09-22
  • 2013-09-22
相关资源
最近更新 更多