有没有人尝试使用相交 table 而不是 oracle-apex 值列表的存储方法

has anyone tried to use an intersect table instead of oracle-apex list of values' storing method

如您所知,ApEx 将值的多项选择列表存储在单个列中,方法是像这样用“:”分隔值

qwe:rty:yui:opa:sdf:ghj

但这不是数据库应有的功能,应该有一个带有外键的中间 table。 所以我的问题是有没有人尝试过以正确的方式去做,或者我只是坚持使用 ApEx 的方法?如果是这样,是否没有出错的风险? 我对 apex 不是很有经验,所以我仍然不知道如何同时插入 2 tables,如果有人能告诉我如何找到我自己的解决方案。

据我所知,要么使用 Apex 提供的内容(以冒号分隔的值列表),要么“发明”自己的解决方案。

我不知道他们 (Oracle) 为什么选择那样做,但是是的 - 这很烦人。您无法将这些值正确存储到 table,无法强制执行引用完整性约束,在编写报告时出现“问题”(因为我们通常存储 ID 并显示 names 所以我们必须将列转换为行;并不是说你做不到,只是说),...

因为我没有(太多)多 select 物品,所以我有点接受我拥有的东西,但我不喜欢它。

multi-select 中的值在 APEX 中被视为冒号分隔的列表,但您拥有存储数据所需的所有自由。没有对 multi selects 的内置支持(可能是因为有很多方法可以在后端实现它)但是自己实现逻辑并不难。

请允许我举个例子。有一个tableTEAMS(主键TEAM_ID)和一个子tableMEMBERS(主键MEMBER_ID)和一个交集table TEAM_MEMBERS(主键 TEAM_MEMBER_ID - 自动生成)。 在团队表单中,有一个类型为 select 列表的页面项目 P1_TEAM_MEMBERS,其中“允许多选”设置为“开”。 这有两个部分:

  1. 在页面加载时从交集 table 获取数据到页面项目中
  2. 处理提交的数据。

(1) 第一部分很简单。您在类型为“SQL 查询(return 冒号分隔值)”的 P1_TEAM_MEMBERS 上创建了一个计算(到 运行 在表单初始化过程之后)。这种类型的计算是专门为处理 multi selects 而创建的。来源是

SELECT member_id FROM team_members WHERE team_id = :P1_TEAM_ID

如果你想有更多的控制,你也可以使用类型“SQL查询(return单值)”和我们LISTAGG将列转换为冒号分隔字符串。

(2) 要处理数据,您可以使用在自动行处理过程之后执行的应用程序过程。这是因为如果你想创建一个有成员的新团队,你需要 master table 的主键值(P1_TEAM 在我们的例子中)。在我的代码中,我使用了另一个页面项目 P1_TEAM_MEMBERS_OLD,它具有团队成员的原始值。它还有一个以冒号分隔的字符串,它是在此页面处理之前计算的。 plsql API apex_string 提供了很多非常有用的功能。 apex_string.split 获取带分隔符的字符串并将其转换为 pl/sql 集合。 使用 MULTISET 来识别新旧值的差异。

DECLARE
  l_old_team_members apex_t_varchar2;
  l_new_team_members apex_t_varchar2;
  l_members_added apex_t_varchar2;
  l_members_removed apex_t_varchar2;
BEGIN
  l_old_team_members := apex_string.split(:P1_MEMBERS_OLD,':');
  l_new_team_members := apex_string.split(:P1_MEMBERS,':');
  l_members_added := l_new_team MULTISET EXCEPT l_old_team;
  l_members_removed := l_old_team MULTISET EXCEPT l_new_team;
  -- add new team members
  FOR i IN 1 .. l_members_added.COUNT LOOP
    INSERT INTO team_members(team_id, member_id)
      VALUES (:P1_TEAM_ID,l_members_added(i));
  END LOOP;
  -- delete removed team members
  FOR i IN 1 .. l_members_removed.COUNT LOOP
    DELETE FROM team_members WHERE team_id = :P1_TEAM_ID AND member_id = l_members_removed(i);
  END LOOP;
END;

此代码的缺点是没有开箱即用的丢失更新检测,但如果需要,您可以手动实施。