尝试使用 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 没有任何意义。您可以在上面一行的 asbegin 之间声明变量。您可以使用 declare 在那里创建一个嵌套的 PL/SQL 块,但是您需要匹配的 beginend 而您没有。
  • 如果您要在 PL/SQL 中使用 case 语句,则需要 end case。您还需要在每个表达式后添加一个分号 ;
  • 您的 insert 语句也缺少一个分号。
  • 从逻辑上讲,我很难想象你真的想在这里有一个 insert。添加新列时在 table 中创建一堆新行没有逻辑意义。我假设您想要 update 现有行中新列的值。这大概需要您的光标 select 是主键列,并且可能会更改您是否分组以及分组依据。
  • Productpriceexecute 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 语句,然后执行它,这样你就可以通过打印出您为调试而构建的语句来调试。