运行 使用正则表达式对列中以分号分隔的值进行复杂查询
Running a complex query on semi-colon separated values in a column using regexp
我有 table 内容元数据。一些列是用户 ID、内容 ID、角色。角色列是“;”分离值。例如,
在上面的 table 中,结果列指示该行是否应出现在查询中。
管理员角色:管理员、实施者、设置
最终用户角色:最终用户 1、最终用户 2、最终用户 3 等。 (这些是虚拟名称,实际名称有很大不同,这里不能透露)。
进一步展开,条件是查询结果行应至少具有一个非管理员最终用户角色。有五个管理员类型角色和大量非管理员最终用户角色。行可以有尽可能多的角色。
以下是我正在考虑的方法:
1. 创建一个包含所有角色的临时 table 并查询 table in where 角色条件,并使用 INSTR 找出最终用户角色。我不想这样做,因为我试图在查询中避免 pl/sql 。
2. 正则表达式
我一直在试验正则表达式,但没有取得任何进展。
注意:请不要建议更改数据布局,因为我无法控制它!
更新:
好的,这是我正在考虑的另一种方法。
- 从列字符串中删除所有与管理员相关的角色。
- 检查列表的长度。 Select 非零长度。
我猜这将需要 5 个替换函数,一个用于每个管理员类型角色,一个用于计算长度(这实际上是计算分号 +1 的数量)。
我正在尝试这个。如果有效,我会更新我的答案。否则邀请更多建议!
这是一个非常糟糕的数据布局。让我假设你不能改变它。有时我们会被其他人非常非常糟糕的设计决定所困。
我还假设用户的层次结构只有一层。如果是这样,您可以使用单个 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 || ';%';
好的,我尝试了最新的方法(有问题的更新),它有点管用。我实施了 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;
更新:我在这里发布我的最终解决方案,以防它可能对其他人有用:
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;
我有 table 内容元数据。一些列是用户 ID、内容 ID、角色。角色列是“;”分离值。例如,
在上面的 table 中,结果列指示该行是否应出现在查询中。
管理员角色:管理员、实施者、设置 最终用户角色:最终用户 1、最终用户 2、最终用户 3 等。 (这些是虚拟名称,实际名称有很大不同,这里不能透露)。
进一步展开,条件是查询结果行应至少具有一个非管理员最终用户角色。有五个管理员类型角色和大量非管理员最终用户角色。行可以有尽可能多的角色。
以下是我正在考虑的方法: 1. 创建一个包含所有角色的临时 table 并查询 table in where 角色条件,并使用 INSTR 找出最终用户角色。我不想这样做,因为我试图在查询中避免 pl/sql 。 2. 正则表达式
我一直在试验正则表达式,但没有取得任何进展。
注意:请不要建议更改数据布局,因为我无法控制它!
更新: 好的,这是我正在考虑的另一种方法。 - 从列字符串中删除所有与管理员相关的角色。 - 检查列表的长度。 Select 非零长度。 我猜这将需要 5 个替换函数,一个用于每个管理员类型角色,一个用于计算长度(这实际上是计算分号 +1 的数量)。 我正在尝试这个。如果有效,我会更新我的答案。否则邀请更多建议!
这是一个非常糟糕的数据布局。让我假设你不能改变它。有时我们会被其他人非常非常糟糕的设计决定所困。
我还假设用户的层次结构只有一层。如果是这样,您可以使用单个 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 || ';%';
好的,我尝试了最新的方法(有问题的更新),它有点管用。我实施了 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;
更新:我在这里发布我的最终解决方案,以防它可能对其他人有用:
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;