在where子句中使用listagg生成的列

时间:2017-04-11 14:10:42

标签: sql oracle listagg

我在oracle数据库中有3个表。它们看起来像这样:

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指向表user中具有相同名称的列,organisationname指向表Organisation

对于在user x上拥有合适用户的所有organisation,我想获得用户拥有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%';  

2 个答案:

答案 0 :(得分: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关键字,因此我们需要两个步骤而不是一个来构建不同组织的列表。)

更新:为了吸引没有任何其他组织的用户,我们会移除条件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;

答案 1 :(得分: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 "organisations" like '%termToSearch%'; 

参考:Schema Object Names and Qualifiers