【问题标题】:Simple Stored Procedure for learning用于学习的简单存储过程
【发布时间】:2021-08-19 09:40:55
【问题描述】:

我的旅程正在取得进展,我正在快速学习。我无法获得足够的这些东西......唉,我在这里陷入了死胡同,需要一些帮助。

我正在运行 Visual Studio,已连接到数据库(其中填充了虚拟数据)。我能够按预期对其运行查询。但是,我现在正在学习程序,但遇到了一个问题。

我正在尝试简单地运行一个从表中选择所有内容的查询。

CREATE PROCEDURE nearthetop()
BEGIN
SELECT * FROM RESULTS WHERE VOLUME = (SELECT MAX(VOLUME) FROM RESULTS WHERE VOLUME NOT In (SELECT Max(VOLUME) from RESULTS))
END;

当我在 Visual Studio 中运行它时出现错误:

EXECUTE FAIL:

  CREATE PROCEDURE twofromtop() BEGIN SELECT * FROM RESULTS WHERE VOLUME = (SELECT MAX(VOLUME) FROM RESULTS WHERE VOLUME NOT In (SELECT Max(VOLUME) from RESULTS)) END

Message :

  You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 3

当我删除 BEGIN 和 END 时;从它创建它的过程来看,它很好。 这是为什么呢?

然后,一旦创建,我如何“调用”该过程以便我可以看到返回的结果?

【问题讨论】:

  • @Littlefoot 提供了一个准确的答案,但错过了一个大项目。对你来说,它属于检查你的基本假设的类别。 PL/SQL 主要是一种 Oracle RDBMS 语言,但您的错误消息完全表明其他内容:查看与您的 MySQL 服务器版本相对应的手册即使 Oracle Corporation 拥有 MySQL并不意味着数据库可以互换。

标签: oracle stored-procedures plsql


【解决方案1】:

在 Oracle 中,当 PL/SQL 代码使用 SELECT 语句时,您必须选择 进入 某些东西 - 局部变量、集合等 - 或使用游标循环并处理游标变量。

您正在选择volume 值第二大的行。您编写的代码工作,但它从同一个表中提取了 3 次,这不是最佳的。例如(基于 Scott 的示例模式),获取第二大薪水:

SQL> select ename, sal from emp order by sal desc;

ENAME             SAL
---------- ----------
KING             5000   --> largest
FORD             3000   --> Ford and Scott both share
SCOTT            3000   --> the 2nd largest salary
JONES            2975
BLAKE            2850
CLARK            2450
<snip>

您的查询返回正确的结果:

SQL> select *
  2  from emp
  3  where sal = (select max(sal) from emp
  4               where sal not in (select max(sal) from emp)
  5              );

     EMPNO ENAME      JOB              MGR HIREDATE        SAL       COMM     DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 09.12.82       3000                    20
      7902 FORD       ANALYST         7566 03.12.81       3000                    20

考虑换一种方式:

SQL> select *
  2  from (select e.*,
  3               rank() over (order by sal desc) rnk
  4        from emp e
  5       )
  6  where rnk = 2;

     EMPNO ENAME      JOB              MGR HIREDATE        SAL       COMM     DEPTNO        RNK
---------- ---------- --------- ---------- -------- ---------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 09.12.82       3000                    20          2
      7902 FORD       ANALYST         7566 03.12.81       3000                    20          2

SQL>

现在,回到您的程序。一个不需要太多努力的简单选项是使用游标FOR 循环。程序的IN 参数表示你想要的最高薪水:

SQL> create or replace procedure nearthetop (par_n in number) as
  2  begin
  3    for cur_r in (select *
  4                  from (select e.*,
  5                          rank() over (order by sal desc) rnk
  6                        from emp e
  7                       )
  8                  where rnk = par_n
  9                 )
 10    loop
 11      dbms_output.put_line(cur_r.ename ||': '|| cur_r.sal);
 12    end loop;
 13  end;
 14  /

Procedure created.

测试:

SQL> set serveroutput on
SQL> begin
  2    nearthetop(2);        --> give me the 2nd largest salary
  3  end;
  4  /
SCOTT: 3000
FORD: 3000

PL/SQL procedure successfully completed.

SQL> begin
  2    nearthetop(5);        --> give me the 5th largest salary
  3  end;
  4  /
BLAKE: 2850

PL/SQL procedure successfully completed.

SQL>

我只是在屏幕上显示这些值;你从来没有说过你想对他们做什么。


如果您想将结果返回给调用者,更好的选择是使用函数而不是过程。在这种情况下,它会返回一个引用游标。

SQL> create or replace function f_nearthetop (par_n in number)
  2    return sys_refcursor
  3  as
  4    rc sys_refcursor;
  5  begin
  6    open rc for select *
  7                  from (select e.*,
  8                          rank() over (order by sal desc) rnk
  9                        from emp e
 10                       )
 11                  where rnk = par_n;
 12    return rc;
 13  end;
 14  /

Function created.

测试:

SQL> var l_rc refcursor
SQL>
SQL> exec :l_rc := f_nearthetop(2);

PL/SQL procedure successfully completed.

SQL> print :l_rc

     EMPNO ENAME      JOB              MGR HIREDATE        SAL       COMM     DEPTNO        RNK
---------- ---------- --------- ---------- -------- ---------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 09.12.82       3000                    20          2
      7902 FORD       ANALYST         7566 03.12.81       3000                    20          2

SQL>

所以,是的 - 有多种选择。您实际使用哪一个取决于您想做什么。

(截至 Visual Studio:我无能为力,我不使用它。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 2011-10-27
    • 2012-02-03
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    相关资源
    最近更新 更多