开发者

SQL Group By with a condition

Scenario: I need to create a report for the auditors for an ASP.Net application. I have a program that parses the XML of the web.config files in a directory for the authorization tag and creates a report providing which users have access to whic开发者_运维百科h folder in the site structure. The report is shown below.

UserName, Firstname, LastName, Directory, Roles, Access, LastLoginDate

SQL Group By with a condition

Problem: As you can see from the report some directories (the middle column with GISMO in it) show up twice, with both allow and deny for a user. I am wondering if there is a way to group the results in such a way that if there is a row that has allow for a directory then the deny's are not shown but otherwise they are.

Alternatively if this can be manipulated in VB.net/C# that is also an option. It comes back there and is pumped into an Excel spreadsheet.

Any help is appreciated. Thanks in advance.

Edit: I should have explained better. I still need the deny rows to show if the user isn't allowed in the directory. But if they are allowed then there is no point showing the deny rows.


This works on an Oracle database, so it should work or get you close on SQL Server as I know SQL Server supports the main component of this, the CASE operation.

CREATE TABLE user_permissions (
     user_role   VARCHAR2(10) NOT NULL,
     dir         VARCHAR2(10) NOT NULL,
     user_access VARCHAR2(5)  NOT NULL
);

INSERT INTO user_permissions VALUES ('admin', 'dir1', 'allow');
INSERT INTO user_permissions VALUES ('admin', 'dir2', 'allow');
INSERT INTO user_permissions VALUES ('power', 'dir1', 'allow'); -- Allow and Deny dir1
INSERT INTO user_permissions VALUES ('power', 'dir1', 'deny');
INSERT INTO user_permissions VALUES ('power', 'dir2', 'deny');
COMMIT;


SELECT UNIQUE j.*
FROM (
       SELECT user_role, dir,
              MAX(CASE user_access WHEN 'allow' THEN 1 ELSE 0 END) allowFlag,
              MAX(CASE user_access WHEN 'deny'  THEN 1 ELSE 0 END) denyFlag
       FROM user_permissions
       GROUP BY user_role, dir
     ) t
JOIN user_permissions j ON (t.user_role = j.user_role AND t.dir = j.dir)
WHERE j.user_access = 'allow' OR (t.allowFlag = 0 and user_access = 'deny');

Results:

USER_ROLE  DIR        USER_ACCESS 
---------- ---------- ----------- 
admin      dir1       allow       
admin      dir2       allow       
power      dir1       allow       
power      dir2       deny        

Basically, you use a pivot table to aggregate the multiple rows into a single row describing the attributes for the directory. Once you have the aggregated row, it's easy to compare the attributes you've declared to join up the rows that you want to display.


If you've got SQL Server 2005 or newer, you can use this:

with cte as (
    select ROW_NUMBER() OVER (partition by username, directory order by access) as row, *
    from report
)
select *
from cte
where row = 1

In the partition clause, put in whatever makes a "group" unique.

Reference: http://msdn.microsoft.com/en-us/library/ms190766.aspx

http://msdn.microsoft.com/en-us/library/ms186734.aspx


Something like this should work but this assumes that your paths were not entered such as /directory/directory/, /directory/Directory/, directory/directory/default.aspx, etc. Your best bet would be to parse the data and remove duplicates at the .NET process level you've created, since parsing at that stage is usually easier.

select derived.*,
       case when exists 
         (select top 1 1 from table_name as t2 where t2.username = derived.username and t2.directory=derived.directory and t2.access = 'allow') then 1 else 0 end as is_allowed,
       case when exists 
         (select top 1 1 from table_name as t2 where t2.username = derived.username and t2.directory=derived.directory and t2.access = 'deny') then 1 else 0 end as is_denied,
from
(
 select distinct t.username, t.firstname, t.lastname, t.directory
  from table_name as t
) as derived


SELECT UserName, Firstname, LastName, Directory, Roles, Access, LastLoginDate 
FROM Report R
WHERE Access = 'allow'
   OR ( Access = 'deny' 
      AND NOT EXISTS
         ( SELECT *
           FROM Report R2
           WHERE R2.Directory = R.Directory
             AND R2.UserName = R.UserName 
             AND R2.Roles = R.Roles
         )
      )

Based on your comments, this line should be removed, so only (UserName, Directory) combination is checked:

             AND R2.Roles = R.Roles
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜