尝试使用 EXECUTE IMMEDIATE,无法编译程序
Trying to use EXECUTE IMMEDIATE, cannot compile procedure
尝试编写一个不接受任何值的过程,向我现有的产品添加促销价列 table,然后循环计算促销价并将其插入新列。
我无法让任何东西工作,我认为这与 Oracle 不喜欢 ALTER TABLE
在过程内部成为 运行 有关,但我不知道,而且我的知识还不足以指导我在其他地方进行尝试。
这是我的尝试
CREATE or REPLACE PROCEDURE ProductLineSale as
BEGIN
DECLARE
NewSalePrice NUMBER(6,2):=0;
EXECUTE IMMEDIATE 'alter table ' || Product || 'add or replace column' || 'SalePrice NUMBER(6,2);'
FOR p in (SELECT ProductStandardPrice FROM Product
group by ProductStandardPrice)
LOOP
CASE WHEN p.ProductStandardPrice>=400 THEN NewSalePrice:=.9*price
WHEN p.ProductStandardPrice<400 THEN NewSalePrice:=.85*price
INSERT INTO Product(SalePrice)
VALUES(NewSalePrice)
END LOOP;
END ProductLineSale
Product 是我数据库中产品 table 的字面名称。 SalePrice 是我希望新列的名称。
SQLDeveloper 不会编译程序。我得到的错误也相当神秘:
Error(2,10): PLS-00103: Encountered the symbol "=" when expecting one of the following: constant exception table long double ref char time timestamp interval date binary national character nchar.
有很多错误...第一次通过时就跳出来的错误。
- 这个要求没有意义。在过程中添加列没有意义。您创建过程是因为您希望代码可重用。添加列只能执行一次,因此根据定义它是不可重复使用的。
- 程序必须先编译才能执行。如果存在对不存在的列的引用,则该过程将无法编译。因此,如果您想使用动态 SQL 向 table 添加一列,则对该列的所有后续引用(即您的
insert
语句)都需要使用动态 SQL还有。
- 您的 DDL 语句不正确。没有
add or replace
子句,它是 alter table product add SalePrice NUMBER(6,2)
。请注意,在构建字符串时,还必须确保子句 add
和列名称 SalesPrice
之间有一个 space -- 您要创建的两个字符串之一重新连接在一起需要那个。
declare
没有任何意义。您可以在上面一行的 as
和 begin
之间声明变量。您可以使用 declare
在那里创建一个嵌套的 PL/SQL 块,但是您需要匹配的 begin
和 end
而您没有。
- 如果您要在 PL/SQL 中使用
case
语句,则需要 end case
。您还需要在每个表达式后添加一个分号 ;
。
- 您的
insert
语句也缺少一个分号。
- 从逻辑上讲,我很难想象你真的想在这里有一个
insert
。添加新列时在 table 中创建一堆新行没有逻辑意义。我假设您想要 update
现有行中新列的值。这大概需要您的光标 select 是主键列,并且可能会更改您是否分组以及分组依据。
Product
和 price
在 execute immediate
语句和 case
语句中用作局部变量但未定义。我猜你只是想硬编码你正在改变的 table 的名称,而 price
应该引用你需要的 table 中的列的名称select 在你的光标中,但我不确定。
这个 case
语句在语法上是有效的(或者如果 price
解析为有效的东西)。由于我上面详述的原因,许多其他更正不太明显。
case when p.ProductStandardPrice>=400
then NewSalePrice:=.9*price;
when p.ProductStandardPrice<400
THEN NewSalePrice:=.85*price;
end case;
如果我要推测你真正想要什么(鉴于这是一项要求实际上没有意义的家庭作业),我猜是这样的
CREATE or REPLACE PROCEDURE ProductLineSale
as
begin
execute immediate 'alter table Product add SalePrice NUMBER(6,2)';
execute immediate 'update product ' ||
' set SalePrice = (case when ProductStandardPrice >= 400 ' ||
' then 0.9 * Price ' ||
' else 0.85 * Price ' ||
' end) ';
end ProductLineSale;
如果你打算使用动态 SQL,声明一个局部变量几乎总是有意义的,在该变量中构建 SQL 语句,然后执行它,这样你就可以通过打印出您为调试而构建的语句来调试。
尝试编写一个不接受任何值的过程,向我现有的产品添加促销价列 table,然后循环计算促销价并将其插入新列。
我无法让任何东西工作,我认为这与 Oracle 不喜欢 ALTER TABLE
在过程内部成为 运行 有关,但我不知道,而且我的知识还不足以指导我在其他地方进行尝试。
这是我的尝试
CREATE or REPLACE PROCEDURE ProductLineSale as
BEGIN
DECLARE
NewSalePrice NUMBER(6,2):=0;
EXECUTE IMMEDIATE 'alter table ' || Product || 'add or replace column' || 'SalePrice NUMBER(6,2);'
FOR p in (SELECT ProductStandardPrice FROM Product
group by ProductStandardPrice)
LOOP
CASE WHEN p.ProductStandardPrice>=400 THEN NewSalePrice:=.9*price
WHEN p.ProductStandardPrice<400 THEN NewSalePrice:=.85*price
INSERT INTO Product(SalePrice)
VALUES(NewSalePrice)
END LOOP;
END ProductLineSale
Product 是我数据库中产品 table 的字面名称。 SalePrice 是我希望新列的名称。
SQLDeveloper 不会编译程序。我得到的错误也相当神秘:
Error(2,10): PLS-00103: Encountered the symbol "=" when expecting one of the following: constant exception table long double ref char time timestamp interval date binary national character nchar.
有很多错误...第一次通过时就跳出来的错误。
- 这个要求没有意义。在过程中添加列没有意义。您创建过程是因为您希望代码可重用。添加列只能执行一次,因此根据定义它是不可重复使用的。
- 程序必须先编译才能执行。如果存在对不存在的列的引用,则该过程将无法编译。因此,如果您想使用动态 SQL 向 table 添加一列,则对该列的所有后续引用(即您的
insert
语句)都需要使用动态 SQL还有。 - 您的 DDL 语句不正确。没有
add or replace
子句,它是alter table product add SalePrice NUMBER(6,2)
。请注意,在构建字符串时,还必须确保子句add
和列名称SalesPrice
之间有一个 space -- 您要创建的两个字符串之一重新连接在一起需要那个。 declare
没有任何意义。您可以在上面一行的as
和begin
之间声明变量。您可以使用declare
在那里创建一个嵌套的 PL/SQL 块,但是您需要匹配的begin
和end
而您没有。- 如果您要在 PL/SQL 中使用
case
语句,则需要end case
。您还需要在每个表达式后添加一个分号;
。 - 您的
insert
语句也缺少一个分号。 - 从逻辑上讲,我很难想象你真的想在这里有一个
insert
。添加新列时在 table 中创建一堆新行没有逻辑意义。我假设您想要update
现有行中新列的值。这大概需要您的光标 select 是主键列,并且可能会更改您是否分组以及分组依据。 Product
和price
在execute immediate
语句和case
语句中用作局部变量但未定义。我猜你只是想硬编码你正在改变的 table 的名称,而price
应该引用你需要的 table 中的列的名称select 在你的光标中,但我不确定。
这个 case
语句在语法上是有效的(或者如果 price
解析为有效的东西)。由于我上面详述的原因,许多其他更正不太明显。
case when p.ProductStandardPrice>=400
then NewSalePrice:=.9*price;
when p.ProductStandardPrice<400
THEN NewSalePrice:=.85*price;
end case;
如果我要推测你真正想要什么(鉴于这是一项要求实际上没有意义的家庭作业),我猜是这样的
CREATE or REPLACE PROCEDURE ProductLineSale
as
begin
execute immediate 'alter table Product add SalePrice NUMBER(6,2)';
execute immediate 'update product ' ||
' set SalePrice = (case when ProductStandardPrice >= 400 ' ||
' then 0.9 * Price ' ||
' else 0.85 * Price ' ||
' end) ';
end ProductLineSale;
如果你打算使用动态 SQL,声明一个局部变量几乎总是有意义的,在该变量中构建 SQL 语句,然后执行它,这样你就可以通过打印出您为调试而构建的语句来调试。