使用regexp对列中的分号分隔值运行复杂查询

时间:2017-06-21 20:56:27

标签: sql oracle oracle-sqldeveloper oracle-apex oracle-apex-5.1

我有一张内容元数据表。一些列是用户ID,内容ID,角色。角色列是';'分开的值。例如, enter image description here

在上表中,“结果”列指示该行是否应出现在查询中。

管理员角色:管理员,执行者,设置 最终用户角色:最终用户1,最终用户2,最终用户3等。 (这些是虚拟名称,实际名称有所不同,这里不能透露)。

要进一步扩展,标准是,查询应该产生具有至少一个非管理员最终用户角色的行。有五个管理员类型角色和大量非管理员最终用户角色。行可以拥有尽可能多的角色。

以下是我正在考虑的方法: 1.创建包含所有角色的临时表,并在角色的条件中查询表,并使用INSTR查找最终用户角色。我不想这样做,因为我试图在我的查询中避免使用pl / sql。 2. Regexp

我一直在试用regexp,但没有随处可见。

注意:请不要建议更改数据布局,因为我无法控制它!

更新: 好的,这是我想的另一种方法。 - 从列字符串中删除所有与管理员相关的角色。 - 检查列表的长度。选择非零长度。 我猜这将需要5个替换函数,一个用于每个管理类型角色,另一个用于计算长度(这将基本上计算分号+1)。 我正在尝试这个。如果有效,我会更新我的答案。否则邀请更多建议!

3 个答案:

答案 0 :(得分:0)

这是一个可怕的,可怕的数据布局。让我假设你无法改变它。有时我们会遇到其他人非常非常糟糕的设计决策。

我还假设用户的层次结构只有一个深度。如果是这样,您可以使用单个join

select c.*,
       (case when ';' || c.roles || ';' like '%;Admin;%' then 'Yes'
             when ';' || cu.roles || ';' like '%;Admin;%' then 'Yes'
             else 'No'
        end) as Outcome
from content c left join
     content cu
     on ';' || c.roles|| ';' like '%;End User ' || cu.id || ';%';

编辑:

如果您有多个管理员角色,只需使用正则表达式:

select c.*,
       (case when regexp_like(';' || c.roles || ';', ';Admin;|;Implementor;|;Setup;') then 'Yes'
             when regexp_like(';' || cu.roles || ';', ';Admin;|;Implementor;|;Setup;') then 'Yes'
             else 'No'
        end) as Outcome
from content c left join
     content cu
     on ';' || c.roles|| ';' like '%;End User ' || cu.id || ';%';

答案 1 :(得分:0)

好的,我尝试了最新的方法(有问题的更新),它有点有效。我实施了3个管理员角色。不得不为此使用长字符串操作。但是,如果列出了3个连续的管理员角色(管理员;设置;实施者;最终用户1),这将无效,因为我将有3';' 。有人可以建议用一个更好的方法来替换一个以上的分号吗?

另外请建议这种方法是否有任何改进。

with new_roles as 
(select id,
 roles,
trim(both ';' from (replace(
    replace(
        replace(
            replace(roles,'Setup',''), 
            'Administrator', ''),
        'Implementor', ''),
    ';;', ';'))) as role_new
 from my_table)

select id, roles, role_new
from new_roles
where (LENGTH(role_new) - LENGTH(REPLACE(role_new,';','')))+1 is not NULL;

答案 2 :(得分:0)

更新:我在这里发布我的最终解决方案,以防它可能对其他人有用:

with new_roles as 
(select id,
 roles,
trim(both ';' from (
    regexp_replace(
    regexp_replace(roles, '(Setup)|(Administrator)|(Implementor)','')),
    ';{1;}',';'))) as role_new
 from my_table)

select id, roles, role_new
from new_roles
where (LENGTH(role_new) - LENGTH(REPLACE(role_new,';','')))+1 is not NULL;