【问题标题】:PL/SQL with Oracle Apex - Delete ValidationPL/SQL 与 Oracle Apex - 删除验证
【发布时间】:2021-09-06 19:57:00
【问题描述】:

假设我有两个 oracle 表: TEST_ENTRIES:

ID NAME CAT_ID
1 Desk 1
2 Arm chair 1
3 Other business stuff 2

和 TEST_CATEGORIES:

ID NAME VISIBLE
1 Furniture 1
2 Consumables 1

我现在想在 PL/SQL 中的 Oracle Apex 中编写一个验证,它检查表 TEST_CATEGORIES 是否在 TEST_ENTRIES 中使用了某个 id,如果没有使用它应该被删除。所以我写了这样的东西:

Declare
  id number;
Begin
  Select count(1) into id 
   from TEST_CATEGORIES
   Where name = :NAME;

  if id > 0 then
        raise_application_error(-20001,'Could not delete from sepecified tables');
  else
    DELETE FROM TEST_CATEGORIES
    WHERE ID = TEST_ENTRIES.CAT_ID
        RETURN;
  end if;
End;

但它不能以这种方式工作。有人可以帮帮我吗?

【问题讨论】:

    标签: sql oracle plsql oracle-apex


    【解决方案1】:

    如果我是你,我会创建一个外键约束并让数据库处理它。像这样的:

    样本数据:

    SQL> select * from test_categories;
    
            ID NAME           VISIBLE
    ---------- ----------- ----------
             1 furniture            1
             2 consumables          1
             3 delete me            1    --> not referenced from TEST_ENTRIES table
    
    SQL> select * from test_entries;
    
            ID NAME         CAT_ID
    ---------- -------- ----------
             1 desk              1
             2 armchair          1
             3 other             2
    

    给TEST_CATEGORIES添加一个主键(否则外键不能引用):

    SQL> alter table test_categories add constraint pk_cat
      2    primary key (id);
    
    Table altered.
    

    向 TEST_ENTRIES 添加外键:

    SQL> alter table test_entries add constraint fk_ent_cat
      2    foreign key (cat_id)
      3    references test_categories (id);
    
    Table altered.
    

    测试:ID = 1 引用自 TEST_ENTRIES,因此 Oracle 不会让您删除它:

    SQL> delete from test_categories where id = 1;
    delete from test_categories where id = 1
    *
    ERROR at line 1:
    ORA-02292: integrity constraint (SCOTT.FK_ENT_CAT) violated - child record
    found
    

    但是,ID = 3 没有被引用,将被成功删除:

    SQL> delete from test_categories where id = 3;
    
    1 row deleted.
    
    SQL>
    

    如果您想创建自己的代码,方法如下;我在 SQL*Plus 中运行它,所以我使用替换变量&&P1_CAT_ID。取而代之的是:P1_CAT_ID(即页面项目)并省略第 14 行,因为它在 Apex 中无用。

    SQL> rollback;
    
    Rollback complete.
    
    SQL> declare
      2    l_cnt number;
      3  begin
      4    select count(*)
      5      into l_cnt
      6      from test_entries e
      7      where e.cat_id = &&P1_CAT_ID;         --> you'd use :P1_CAT_ID
      8
      9    if l_cnt > 0 then
     10       raise_application_error(-20000, 'Not allowed, child records exist');
     11    else
     12       delete from test_categories
     13         where id = &&P1_CAT_ID;            --> you'd use :P1_CAT_ID
     14       dbms_output.put_line(sql%rowcount ||' row(s) deleted');
     15    end if;
     16  end;
     17  /
    Enter value for p1_cat_id: 1
    declare
    *
    ERROR at line 1:
    ORA-20000: Not allowed, child records exist
    ORA-06512: at line 10
    
    
    SQL> undefine p1_cat_id
    SQL> /
    Enter value for p1_cat_id: 3
    1 row(s) deleted
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    【讨论】:

      【解决方案2】:

      可以这样做,但这不是验证。验证旨在验证用户输入。例如,如果用户无法选择在结束日期之后的开始日期 - 这可能会导致验证失败。如果验证失败,则不执行页面进程。

      页面进程用于使用遗留进程或自定义 pl/sql 执行 dml 操作(更新/插入/删除)

      您在问题中提到使用了某个 id - 这是什么意思?它是用户在表单中选择的值吗?我假设它是我下面代码中的一个页面项

      在您的情况下,代码将分为两部分

      验证
      SELECT 1 
         FROM test_categories
         WHERE name = :P1_NAME;
      
      页面处理
      BEGIN
        DELETE FROM test_categories WHERE name = :P1_NAME;
      END;
      

      请注意,我没有关注代码,而是更多地关注本示例中 APEX 中的 where 逻辑。正如@Littlefoot 指出的那样,您最好使用外键约束来防止意外删除。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多