有没有人尝试使用相交 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
,其中“允许多选”设置为“开”。
这有两个部分:
- 在页面加载时从交集 table 获取数据到页面项目中
- 处理提交的数据。
(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;
此代码的缺点是没有开箱即用的丢失更新检测,但如果需要,您可以手动实施。
如您所知,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
,其中“允许多选”设置为“开”。
这有两个部分:
- 在页面加载时从交集 table 获取数据到页面项目中
- 处理提交的数据。
(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;
此代码的缺点是没有开箱即用的丢失更新检测,但如果需要,您可以手动实施。