Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何在Oracle DB中按同一列中的多个值分组_Sql_Oracle - Fatal编程技术网

Sql 如何在Oracle DB中按同一列中的多个值分组

Sql 如何在Oracle DB中按同一列中的多个值分组,sql,oracle,Sql,Oracle,我有一个用于用户访问软件应用程序的表。用户可以通过字母数字ID表示的应用程序的不同方面进行多次访问。类似地,多个用户可能具有相同或不同的访问集。 例如 我想根据同一组访问对客户进行分组。例如: USER | GROUP ----------------------------------------- Cust1 | Group1 Cust2 | Group

我有一个用于用户访问软件应用程序的表。用户可以通过字母数字ID表示的应用程序的不同方面进行多次访问。类似地,多个用户可能具有相同或不同的访问集。 例如

我想根据同一组访问对客户进行分组。例如:

USER             |       GROUP                  
-----------------------------------------
Cust1            |       Group1
Cust2            |       Group1
Cust3            |       Group2
目前,我已为此目的为一些重要用户创建了如下表:

Table USERGROUP
GROUP             |       ACCESS                  
-----------------------------------------
Group1            |       BA1
Group1            |       BB2
Group2            |       CB1
Group2            |       BA1
下面的查询将比较这两个表

select a.USER,u.GROUP from ACCESSTAB a, USERGROUP u where not exists
(select USERACCESS from ACCESSTAB where USER=a.USER order by 1
MINUS
select ACCESS from USERGROUP where GROUP=u.GROUP order by 1)
我希望在不使用USERGROUP表的情况下对用户进行分组,因为很难为所有用户进行维护,更不用说添加访问需要手动配置。表现并不重要


欢迎提供任何建议/帮助。提前谢谢

看来你的关系是:

  • 用户具有一个或多个权限
  • 用户属于一个或多个组
  • 组具有一个或多个权限

  • 当你说“难以为所有用户维护”时,你并不完全清楚你的意思,但你可能会说用户的权限集(#1)和组的权限集(#3)必须是相等的集,并且你担心保持它们之间的一致性将是困难的。如果我的假设是正确的,那么我建议您删除规则#1,删除ACCESSTAB表,并将USERGROUP表重命名为GROUP#u ACCESS。这将消除更新异常。

    同意@jeff6times7的观点,即您应该重新考虑您的数据模型,使访问组成为驱动型的,但同时。。。您可以使用
    listag()
    为每个用户生成访问权限列表:

    并从不同的聚合生成组:

    select 'Group' || rownum as groupname, groupaccess
    from (
      select distinct listagg(useraccess, ',') within group (order by useraccess) as groupaccess
      from accesstab
      group by username
      order by groupaccess
    );
    
    GROUPNAME GROUPACCESS         
    --------- --------------------
    Group1    BA1,BB2             
    Group2    BA1,CB1             
    
    并将其连接在一起,例如使用两个CTE:

    with user_cte (username, groupaccess) as (
      select username, listagg(useraccess, ',') within group (order by useraccess)
      from accesstab
      group by username
    ),
    group_cte (groupname, groupaccess) as (
      select 'Group' || rownum, groupaccess
      from (
        select distinct listagg(useraccess, ',') within group (order by useraccess) as groupaccess
        from accesstab
        group by username
        order by groupaccess
      )
    )
    select u.username, g.groupname
    from user_cte u
    join group_cte g on g.groupaccess = u.groupaccess
    order by u.username;
    
    USERNAME GROUPNAME
    -------- ---------
    Cust1    Group1   
    Cust2    Group1   
    Cust3    Group2   
    
    或者,您可以使用第一个CTE构建第二个CTE,以便只命中实际表一次:

    with user_cte (username, groupaccess) as (
      select username, listagg(useraccess, ',') within group (order by useraccess)
      from accesstab
      group by username
    ),
    group_cte (groupname, groupaccess) as (
      select distinct 'Group' || dense_rank () over (order by groupaccess), groupaccess
      from user_cte
    )
    select u.username, g.groupname
    from user_cte u
    join group_cte g on g.groupaccess = u.groupaccess
    order by u.username;
    
    USERNAME GROUPNAME
    -------- ---------
    Cust1    Group1   
    Cust2    Group1   
    Cust3    Group2   
    
    或者即使没有第二个CTE:

    with user_cte (username, groupaccess) as (
      select username, listagg(useraccess, ',') within group (order by useraccess)
      from accesstab
      group by username
    )
    select distinct username,
      'Group' || dense_rank() over (order by groupaccess) as groupname
    from user_cte;
    
    USERNAME GROUPNAME
    -------- ---------
    Cust1    Group1   
    Cust2    Group1   
    Cust3    Group2   
    
    (…这几乎是xQbert的方法)

    如果有用,还可以在输出中包含聚合的
    groupaccess
    ,以列出每个组中的权限,但这似乎不是必需的


    当然,一旦使用不同的访问组合添加(或更新)了用户,就会生成(或删除)一个组,并且现有组的编号可能会改变——这可能会让人困惑,但对您来说不是问题。如果这是一个问题,那么您必须维护中间表。

    只是一个简单的例子:

    with AccessTab as 
    (SELECT '1' muser ,'BA1' useraccess from dual UNION ALL
    SELECT '1','BB2' from dual UNION ALL
    SELECT '2','BA1' from dual UNION ALL
    SELECT '2','BB2' from dual UNION ALL
    SELECT '3','CB1' from dual UNION ALL
    SELECT '3','BA1' from dual),
    cte as (SELECT muser, listagg(userAccess,',') within group (order by useraccess) GRP From AccessTab group by muser)
    SELECT A.muser, dense_Rank() over ( order by a.GRP) as mGroup  
    FROM cte a
    
    结果:

    Muser    mGroup
    2        1
    1        1
    3        2
    

    这可以通过listag()函数完成

    SELECT USER, LISTAGG(USERACCESS, ', ') WITHIN GROUP (ORDER BY USER) AS USER_ACCESS_GROUP
    FROM ACCESSTAB
    GROUP BY USER
    
    结果将是

    USERNAME| USER_ACCESS_GROUP
    Cust1     BA1, BB2             
    Cust2     BA1, BB2             
    Cust3     BA1, CB1
    

    如果您对这些组中的每个组都有一个特殊的名称,您可以将listag()包装在DECODE()函数中。

    hakish的方法是按访问顺序列出不同的访问顺序,然后根据这些值加入用户,并添加一个窗口排名来定义您的组。一种不太老练的方法是对每个用户使用完全外部连接计数不同的访问,如果计数与其他用户匹配,则他们拥有相同的组,并再次使用密集秩分析获得一个组,这也是我的首选,但该表不能作为遗留系统的一部分删除,并且依赖于其他表(不知道为什么会这样设计).关于维护问题,我有25000多个用户,他们似乎拥有各种各样的访问权限,每个用户有多达25个访问权限,配置需要手动完成。我必须亲自检查这一点,以确保连接不会超过列的最大长度,幸运的是它没有。我想知道一个人如何我可以不使用Listag来做。但这是另一个问题,下次再问。谢谢。
    SELECT USER, LISTAGG(USERACCESS, ', ') WITHIN GROUP (ORDER BY USER) AS USER_ACCESS_GROUP
    FROM ACCESSTAB
    GROUP BY USER
    
    USERNAME| USER_ACCESS_GROUP
    Cust1     BA1, BB2             
    Cust2     BA1, BB2             
    Cust3     BA1, CB1