问题描述
我有一个通过Oracle github(https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance)上的docker镜像构建的oracle 19c ee数据库。我正在尝试按照他们的示例来介绍如何创建函数from here。
我完全复制了他们的示例。设置表和数据:
CREATE TABLE orders (
customer_id number(10),order_total NUMBER(11,2)
);
INSERT INTO orders (customer_id,order_total) VALUES (1,200.01)
实际功能:
CREATE FUNCTION get_bal(acc_no IN NUMBER)
RETURN NUMBER
IS acc_bal NUMBER(11,2);
BEGIN
SELECT order_total
INTO acc_bal
FROM orders
WHERE customer_id = acc_no;
RETURN(acc_bal);
END;
但是,当我尝试创建函数时,我一直遇到此错误
Query 2 ERROR: ORA-06550: line 5,column 27:
PL/SQL: ORA-00904: "ACC_NO": invalid identifier
ORA-06550: line 2,column 7:
PL/SQL: SQL Statement ignored
ORA-06550: line 6,column 7:
PLS-00372: In a procedure,RETURN statement cannot contain an expression
ORA-06550: line 6,column 7:
PL/SQL: Statement ignored
我在做什么错了?
解决方法
这个例子对我有用。您一定输入了错误的内容。您确定您的功能与手册中的功能完全相同吗?
ORA-00904:“ ACC_NO”:无效的标识符
建议声明acc_bal NUMBER(11,2);
丢失或不同。
PLS-00372:在过程中,RETURN语句不能包含表达式
表示您的代码是一个过程,而不是一个函数。
SQL> CREATE TABLE orders (
2 customer_id number(10),3 order_total NUMBER(11,2)
4 );
Table created
SQL> INSERT INTO orders (customer_id,order_total) VALUES (1,200.01);
1 row inserted
SQL> CREATE FUNCTION get_bal(acc_no IN NUMBER)
2 RETURN NUMBER
3 IS acc_bal NUMBER(11,2);
4 BEGIN
5 SELECT order_total
6 INTO acc_bal
7 FROM orders
8 WHERE customer_id = acc_no;
9 RETURN(acc_bal);
10 END;
11 /
Function created
SQL> select get_bal(1) from dual;
GET_BAL(1)
----------
200.01
顺便说一句,虽然我通常是Oracle文档的忠实拥护者,并且该示例确实说明了如何创建PL / SQL函数,但我认为它可以改进:
- 出于可读性考虑,最好为每个声明分配自己的行,因此最好将行3分成两行,并在行上
acc_bal NUMBER(11,2);
。 -
IS
和AS
关键字在此处可以互换,但是肯定create ... as
(类似于您用来创建表或视图的内容)的读取效果比create ... is
好。 - 可以理解,作者并不想在解释之前通过引入
%type
来使示例复杂化,但是更高级的版本将使用acc_bal orders.order_total%type;
来使acc_bal
继承其数据类型。从表列而不是对其进行硬编码。这适用于该函数中使用的所有三个值。 - 参数和变量的名称还可以-至少是明确的-但是,对于与表列相同的参数和变量使用命名方式时,存在危险。有一天,您将输入
WHERE c.customer_id = customer_id
,并想知道为什么返回的行比预期的多。同样,作者不想在第一个示例中进入整个讨论也是可以理解的,但这是需要考虑的事情。您可以在函数内使用get_bal.acc_no
,或将camelCase用作参数和变量,或将p_
前缀作为'parameter'等。 - 布局的基本规则是,诸如
if/else
和begin/end
之类的开始和结束关键字应左对齐。第10行的END
在其开口BEGIN
下未对齐。我认为在第一行之后缩进整个内容是一种有效的个人布局选择,但对我而言,它不会添加任何内容。 - 一个好主意是在每个SQL语句的周围留空行,以避免出现坚固的文本墙。就个人而言,我希望第9行的
RETURN
前留空行。 -
RETURN
子句不需要任何括号。编译器将忽略第9行的多余括号。我会丢失它们。 - 这是一个好习惯(尽管是可选的),在结尾
END
中包含过程/函数名称,因此第10行将变为END get_bal;
- COBOL风格的大写习惯在行业中很普遍,但没有必要。 (PL / SQL的语法著名地基于Ada,尽管有些语法也指向ALGOL和PL / 1-从来没有大写过。)我将通过简化整个内容来提高可读性。
有了这些更改,我得到了:
create or replace function get_bal
( inAccNo in orders.customer_id%type )
return orders.order_total%type
as
accBal orders.order_total%type;
begin
select order_total into accBal
from orders
where customer_id = inAccNo;
return accBal;
end;