简体   繁体   中英

How to return a single row aggregating data in multiple rows in SQL

I have a table of UserIds and rolenames.

For example:

UserId  Rolename
1       Admin
1       Editor
1       Other
2       Admin
3       Other

I want to return a single row per user containing UserId, IsAdmin, IsEditor , where the latter two columns are booleans representing whether or not the user has the "Admin" role or "Editor" role.

From the above example I would get the following output:

UserId   IsAdmin  IsEditor
1        True     True
2        True     False
3        False    False

Any thoughts? I've been trying all sorts of things with aggregate functions in group by, sub selects etc., but I'm just not getting it.

One possible solution:

SELECT
    UserId,
    CASE WHEN EXISTS (SELECT * FROM #UserRoles A WHERE A.UserId = UR.UserId AND A.Rolename = 'Admin') THEN 'True' ELSE 'False' END AS IsAdmin,
    CASE WHEN EXISTS (SELECT * FROM #UserRoles E WHERE E.UserId = UR.UserId AND E.Rolename = 'Editor') THEN 'True' ELSE 'False' END AS IsEditor
FROM
    UserRoles UR
GROUP BY
    UR.UserId

Whether or not that's valid syntax depends on what type of SQL you're using - Oracle? You didn't specify.

Another possible solution:

SELECT
    U.UserId,
    CASE WHEN A.UserId IS NOT NULL THEN 'True' ELSE 'False' END AS IsAdmin,
    CASE WHEN E.UserId IS NOT NULL THEN 'True' ELSE 'False' END AS IsEditor
FROM
    (
    SELECT DISTINCT
        UserId
    FROM
        UserRoles UR
    ) U
LEFT OUTER JOIN UserRoles A ON A.UserId = U.UserId AND A.Rolename = 'Admin'
LEFT OUTER JOIN UserRoles E ON E.UserId = U.UserId AND E.Rolename = 'Editor'

These solutions also both assume that you will never have multiple rows for the same user id with the same exact role name. For example, User ID 1 with Admin twice in the table.

with data as (
select 1 userid, 'Admin' rolename from dual union all
select 1 userid,       'Editor' rolename from dual union all
select 1 userid,      'Other' rolename from dual union all
select 2 userid,      'Admin' rolename from dual union all
select 3 userid,      'Other' rolename from dual
)
select userid, 
max(case when rolename = 'Admin' then 'True' else 'False' end) isadmin,
max(case when rolename = 'Editor' then 'True' else 'False'  end) iseditor ,
max(case when rolename = 'Other' then 'True' else 'False'  end) isother
from data 
group by userid

OUTPUT:

USERID     ISADMIN ISEDITOR ISOTHER
---------- ------- -------- -------
     1     True    True     True    
     2     True    False    False   
     3     False   False    True    

users :

  UserId   UserName

    1        amir  
    2        john  
    3        sara  

user roles :

  UserId   RoleName

    1        Admin  
    1        Editor  
    2        Editor  

query :

   select UserId , 
     (select count(UserRoles.UserId) from userRoles where userRoles.UserId=users.UserId and RoleName='Admin' ) as IsAdmin ,
     (select count(userRoles.UserId) from userRoles where userRoles.UserId=users.UserId and RoleName='Editor' ) as IsEditor
    from users;

result :

 UserId      IsAdmin   IsEditor
    1          1          1
    2          0          1
    3          0          0

There are a few ways to do it. Assuming that your table is named USERROLE, this works with your sample data on DB2 for i 6.1:

WITH adminrole(UserId, RoleName) AS (
  SELECT UserId, RoleName FROM userrole WHERE RoleName = 'Admin'),

editorrole(UserId, RoleName) AS (
  SELECT UserId, RoleName FROM userrole WHERE RoleName = 'Editor'),

groupid(UserId) AS (
  SELECT UserId FROM userrole GROUP BY UserId)

SELECT groupid.UserId,
       CASE WHEN adminrole.RoleName = 'Admin'
            THEN 'True' ELSE 'False' END AS IsAdmin,
       CASE WHEN editorrole.RoleName = 'Editor'
            THEN 'True' ELSE 'False' END AS IsEditor
FROM groupid LEFT OUTER JOIN adminrole
                  ON groupid.UserId = adminrole.UserId
             LEFT OUTER JOIN editorrole
                  ON groupid.UserId = editorrole.UserId

Output from STRSQL looks like:

....+....1....+....2....+....3...
       USERID   ISADMIN  ISEDITOR
            1    True     True   
            2    True     False  
            3    False    False  
********  End of data  ********  

The USERID column is defined as INTEGER in my test data.

Should work anywhere from V5R3 up to current. Change the table name from USERROLE to whatever your table name is.

There are various changes that can be made, but more info would be needed to know what would really be a good structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM