SQL Server Need SQL query for top values when key value is repeated in table

2skhul33  于 2023-08-02  发布在  其他
关注(0)|答案(3)|浏览(103)

I'm not sure if I described it correctly. I have a list of servers, users and permissions.
The permissions is in there multiple times because it could be in there in multiple groups. This is a gerneral format to the data.
| system | userid | role |
| ------------ | ------------ | ------------ |
| server1 | bill | user |
| server1 | bill | administrator |
| server1 | joe | user |
| server1 | ted | administrator |
| server2 | bill | user |
| server2 | joe | remote_user |
| server2 | joe | user |
| server3 | ted | administrator |
| server3 | ted | remote_user |
| server3 | bill | user |

What I am looking to return is the highest permission set. Administrator is above remote_user. Remote_user is above user.

systemuseridrole
server1billadministrator
server1joeuser
server1tedadministrator
server2billuser
server2joeremote_user
server3tedadministrator
server3billuser

Thanks for any suggestions offered.

I tried finding some examples with 'With' but most examples involve averages.

x6yk4ghg

x6yk4ghg1#

You can use ROW_NUMBER() to find the rows you want, according to any ordering criteria, specified by the ORDER BY clause.

For example:

select *
from (
  select t.*,
    row_number() over(partition by system, userid
      order by case when role = 'administrator' then 3
                    when role = 'remote_user' then 2
                    when role = 'user' then 1
                    else 0 
               end desc) as rn
  from t
) x
where rn = 1
sr4lhrrt

sr4lhrrt2#

Just adding an alternative technique, something I'd call double shuffle:

SELECT  system, userid
,   CASE MAX(CASE role WHEN 'administrator' THEN 3 WHEN 'remote_user' THEN 2 WHEN 'user' THEN 1 ELSE 0 END) WHEN 3 THEN 'administrator' WHEN 2 THEN 'remote_user' WHEN 1 THEN 'user' ELSE 'unknown' END
FROM    (
    VALUES  (N'server1', N'bill', N'user')
    ,   (N'server1', N'bill', N'administrator')
    ,   (N'server1', N'joe', N'user')
    ,   (N'server1', N'ted', N'administrator')
    ,   (N'server2', N'bill', N'user')
    ,   (N'server2', N'joe', N'remote_user')
    ,   (N'server2', N'joe', N'user')
    ,   (N'server3', N'ted', N'administrator')
    ,   (N'server3', N'ted', N'remote_user')
    ,   (N'server3', N'bill', N'user')
) t (system,userid,role)
GROUP BY system, userid
ORDER BY system, userid

First you convert the text to a number level which can be aggregated on, then you convert it back to the text representation.

but5z9lq

but5z9lq3#

You could simply tag the elements with a prefix that's rankable and then strip it out at the end. This would work on a system without analytic functions. It also doesn't involve translating values back and forth so the ranking expression only needs to be written a single time:

select system, userid,
    stuff(max(
        case role
            when 'user'          then 'A'
            when 'remote_user'   then 'B'
            when 'administrator' then 'C'
        end + role), 1, 1, '') as highest_role
from T
group system, userid;

相关问题