SQL Group By с условием - PullRequest
       17

SQL Group By с условием

2 голосов
/ 16 августа 2011

Сценарий : мне нужно создать отчет для аудиторов для приложения ASP.Net. У меня есть программа, которая анализирует XML файлов web.config в каталоге для тега авторизации и создает отчет, предоставляющий пользователям доступ к какой папке в структуре сайта. Отчет показан ниже.

Имя пользователя, Имя, Фамилия, Каталог, Роли, Доступ, LastLoginDate

enter image description here

Проблема : Как вы можете видеть из отчета, некоторые каталоги (средний столбец с GISMO в нем) отображаются дважды, как для пользователя, так и для разрешения. Мне интересно, есть ли способ сгруппировать результаты таким образом, чтобы, если есть строка, в которой есть каталог, то отрицаемые не отображаются, но в противном случае они есть.

В качестве альтернативы, если этим можно манипулировать в VB.net/C#, это тоже опция. Он возвращается туда и закачивается в электронную таблицу Excel.

Любая помощь приветствуется. Заранее спасибо.

Редактировать : Мне следовало объяснить лучше. Мне все еще нужны запрещающие строки, чтобы показать, не разрешен ли пользователь в каталоге. Но если они разрешены, то нет смысла показывать запрещающие строки.

Ответы [ 4 ]

4 голосов
/ 16 августа 2011

Это работает с базой данных Oracle, поэтому оно должно работать или приближать вас к SQL Server, поскольку я знаю, что SQL Server поддерживает основной компонент этого, операцию CASE.

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');

Результаты:

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

По сути, вы используете сводную таблицу, чтобы объединить несколько строк в одну строку, описывающую атрибуты каталога.Получив объединенную строку, легко сравнить объявленные вами атрибуты, чтобы объединить строки, которые вы хотите отобразить.

2 голосов
/ 16 августа 2011

Если у вас SQL Server 2005 или новее, вы можете использовать это:

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

В предложении partition укажите все, что делает "группу" уникальной.

Ссылка: http://msdn.microsoft.com/en-us/library/ms190766.aspx

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

1 голос
/ 17 августа 2011
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
         )
      )

Исходя из ваших комментариев, эту строку следует удалить, поэтому проверяется только комбинация (UserName, Directory):

             AND R2.Roles = R.Roles
1 голос
/ 16 августа 2011

Что-то вроде этого должно работать, но это предполагает, что ваши пути не были введены, такие как / directory / directory /, / directory / Directory /, directory / directory / default.aspx и т. Д. Лучше всего было бы проанализировать данныеи удалите дубликаты на уровне процесса .NET, который вы создали, поскольку анализ на этом этапе обычно проще.

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
...