ORACLE APEX:如何在没有循环的情况下更新 APEX_APPLICATION.G_F01 中的所有项目

ORACLE APEX: How to update all items in APEX_APPLICATION.G_F01 without a LOOP

我在 apex 应用程序的交互式报告中使用复选框。假设它呈现 table MY_TABLE 此 table 包含一个 FLAG 列,其值为 0 or 1

在报告中,如果 FLAG=1

,则勾选每一行的复选框
APEX_ITEM.CHECKBOX2(
            p_idx => 1,
            p_value => lrg_name,
            p_attributes => DECODE(flag,1,'CHECKED', 'null'))

我想允许用户 select 或 deselect 任何行。之后我需要相应地更新数据库中的 FLAG 列。 例如如果用户:

  1. 将 2 行(A1、A2)从 选中更改为未选中
  1. 将 3 行(B1、B2、B3)从 未选中更改为选中

我了解到 APEX_APPLICATION.G_F01 将仅包含选中复选框的行的值。这意味着我可以更新数组中存在的 B1,B2,B3 行,但不能更新 A1,A2.

所以,作为黑客,我所做的是:

  1. MY_TABLE
  2. 中的所有行设置 FLAG=0
  3. 循环 APEX_APPLICATION.G_F01 并设置 FLAG=1
BEGIN
-- step 1
UPDATE MY_TABLE SET FLAG=0;

-- step 2
FOR I in 1..APEX_APPLICATION.G_F01.COUNT
LOOP 
     UPDATE MY_TABLE 
     SET FLAG=1 
     WHERE LRG_NAME=APEX_APPLICATION.G_F01(i);
END LOOP;
END;
如果列表很长,上面的

Step2 会花费很多时间。它 运行 每行一个更新查询。我怎样才能 运行 一次可以更新所有行的查询?

我尝试使用 APEX_UTIL.TABLE_TO_STRING 但它对我不起作用:

UPDATE MY_TABLE SET FLAG=1 
WHERE LRG_NAME IN APEX_UTIL.TABLE_TO_STRING(APEX_APPLICATION.G_F01);

apex_item.checkbox 的问题在于它只有在选中时才有值,因此您没有足够的信息来了解哪些行已从选中变为未选中或相反。您可以通过添加额外的 apex_item.hidden 列并使用 pl/sql 过程中的列进行更新来解决这个问题。

这样您就可以优化 pl/sql 块以仅更新实际需要更改的行。在您的情况下,您总是更新 all 行。下面的代码只会更新更改的行。

示例:

基本 table 带有标志列。我使用的是 apex_item.checkbox(不是 checkbox2),但这不重要。

-- create tables
create table so_checkbox (
    id                             number generated by default on null as identity 
                                   constraint so_checkbox_id_pk primary key,
    name                           varchar2(100 char) not null,
    favorite_flag                  varchar2(1 char) not null
)
;

-- load data
 
insert into so_checkbox (id, name, favorite_flag ) values (1, 'Zero Data Loss Implementation', 'N');
insert into so_checkbox (id, name, favorite_flag ) values (2, 'DevOps Best Practices', 'N');
insert into so_checkbox (id, name, favorite_flag ) values (3, 'New Hire Training', 'N');
insert into so_checkbox (id, name, favorite_flag ) values (4, 'Corporate Network Upgrade', 'N');
insert into so_checkbox (id, name, favorite_flag ) values (5, 'Continuous Build', 'N');

使用 sql 查询创建关于此 table 的交互式报告:

select ID,
       NAME,
       APEX_ITEM.CHECKBOX(1,id,CASE WHEN FAVORITE_FLAG = 'Y' THEN 'CHECKED' END)||
       APEX_ITEM.HIDDEN(2,CASE WHEN FAVORITE_FLAG = 'Y' THEN id END) as favorite
  from SO_CHECKBOX

在第一列中,连接了 2 apex_item 列。第一个是复选框(id 1),第二个(隐藏)是复选框的当前值(id 2)。在提交时运行的过程中,每个数组都放在类型为 apex_t_varchar2 的变量中,然后 pl/sql MULTISET 语句可用于识别更改的复选框。

DECLARE
  l_old_checked apex_t_varchar2 := apex_t_varchar2();
  l_new_checked apex_t_varchar2 := apex_t_varchar2();
  l_added apex_t_varchar2 := apex_t_varchar2();
  l_removed apex_t_varchar2 := apex_t_varchar2();
BEGIN
  FOR i in 1..APEX_APPLICATION.G_F01.COUNT LOOP 
    apex_string.push(l_new_checked,APEX_APPLICATION.G_F01(i));
  END LOOP;
  FOR i in 1..APEX_APPLICATION.G_F02.COUNT LOOP 
    apex_string.push(l_old_checked,APEX_APPLICATION.G_F02(i));
  END LOOP;
  l_added := l_new_checked MULTISET EXCEPT l_old_checked;
  l_removed := l_old_checked MULTISET EXCEPT l_new_checked;
  UPDATE so_checkbox SET favorite_flag = 'Y' WHERE id IN (SELECT column_value FROM table(l_added));
  UPDATE so_checkbox SET favorite_flag = 'N' WHERE id IN (SELECT column_value FROM table(l_removed));
END;