2017-04-11 124 views
0

我在oracle数据库中有3个表。他们是这样的:在where子句中使用listagg生成的列

Table User: 

username|forename|surname 
a   a  a 
b   b  b 
c   c  c 


Table Right: 

username|organisationname|right 
a   x    user 
a   x    admin 
a   x    owner 
a   y    user 
a   y    admin 
a   z    owner 
b   x    user 
c   y    user 
c   y    admin 
c   z    user 

Table Organisation: 

organisationname|number 
x     12 
y     14 
z     42 

Right有两个foreign_keys:username点具有相同名称的表userorganisationnameOrganisation列。

对于在organisation x上有合适用户的所有user,我想获得用户拥有1个或更多权限的所有organisations(组织x除外)的列表。

在我的示例中: a在x上有正确的用户,b在x上有正确的用户,c在x上没有正确的用户。 所以我只想为用户a和b(而不是c!)获得所有组织(独特!,无组织名称两次)。 如果一个用户对x以外的其他组织没有权利(他必须拥有合适的用户),我希望该用户在输出中但没有组织。

的预期结果是:

user|organisations 
a y; z 
b 

我希望你明白我的意思。 我的查询到目前为止是这样的:

select username, 
/* listagg put all the organisationnames of one user in one column separated by ; 
    then the organsation x gets removed from the result*/ 
regexp_replace (listagg (organisationname, '; ') 
     within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') as "organisations" 
from(
    select u2.username as username, 
      o.organisationname as organisationname, 
      /*I do this to remove duplicate entries in the list of organisations of one user */ 
      row_number() over (partition by u2.username, o.organisationname order by u2.username) as rn 
     from RIGHT r2, ORGANISATION o, USER u2 
     where r2.organisationname = o.organisationname 
     and r2.username = u2.username 
     and r2.username IN 
      (
      select u.username 
      from USER u, right r 
      where r.username = u.username 
      and r.right = 'user' 
      ) 
    order by u2.username, o.organisationname   
) 
where rn = 1 
group by username 

该查询工作,但现在我想在列组织进行筛选。但是我无法在where子句中使用它。当我尝试使用它时,oracle会抛出错误: ORA-00904:无效标识符

有谁知道我该如何实现这一目标?我认为oracle由于分析函数listagg而存在问题。 我也很乐意提出如何简化查询的建议。谢谢!

这里是我试图使用列组织在where子句中:

select * from (***long query shown above***) 
where organisations like '%termToSearch%'; 
+0

你能也发帖,你目前在尝试什么,这给你的错误 –

+0

我把问题的末尾where-clause查询 – Markus

回答

2

一步一步:用户名用户| x,则不同的用户| X以外的组织,那么每个用户名聚合:

select 
    username, 
    listagg(organisationname, '; ') within group (order by organisationname) as organisations 
from 
(
    select distinct username, organisationname 
    from right 
    where username in 
    (
    select username 
    from right 
    where organisationname = 'x' and right = 'user' 
) 
    and organisationname <> 'x' 
) 
group by username; 

(不幸的是LISTAGG不接受DISTINCT关键字,所以我们需要两个步骤,而不是一个建立不同的组织的名单。)

UPDATE:为了让用户无需任何其他组织,我们也想删除的条件and organisationname <> 'x'和添加的情况下,构建以LISTAGG

select 
    username, 
    listagg(case when organisationname <> 'x' then organisationname end, '; ') 
    within group (order by organisationname) as organisations 
from 
(
    select distinct username, organisationname 
    from right 
    where username in 
    (
    select username 
    from right 
    where organisationname = 'x' and right = 'user' 
) 
) 
group by username; 
+0

感谢Thorsten。你的查询看起来比我的查询简单得多(我可以在where子句中使用组织)。但我认为你的查询不会给我正确的结果。在我的例子中,我有用户b,他在组织x上拥有合适的用户,但在其他组织中没有权利。我想在我的输出中有这个用户(没有任何组织)。通过查询,此用户不在输出中,因为您只是查找不在组织x上的权限。 – Markus

+0

你说得对。我添加了一个应该可以工作的查询。 –

+0

非常感谢!它现在的作品:) – Markus

1

更改代码的一部分,在那里你要添加别名,

旧代码 -

within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') as "organisations" 

新代码 -

within group (order by organisationname), '(^x;?)|(?x;)|(; x$) ', '') organisations 

新代码 -

within group (order by organizationname), '(^x;?)|(?x;)|(; x$) ', '') as "ORGANISATIONS" 

如果你仍然想使用旧代码,你可以改变的最后一个where条件为 -

where "organisations" like '%termToSearch%'; 

参考: Schema Object Names and Qualifiers

+0

谢谢!你的两个解决方案都行得通!当我用大写字母而不是小写字母写“组织”时,你能解释为什么它有效吗? – Markus

+0

@Markus - 更新后的答案,参考链接解释了如何命名和存储数据库对象。 –

+1

@Markus:用引号告诉DBMS你希望这个区分大小写。没有引号Oracle以大写字母内部存储名称。这就是为什么'组织=组织=组织=“组织”=“组织”。 (顺便说一句,'as'没有什么区别。) –