2008-11-18 17 views
6

Pracuję z istniejącą bazą danych i próbuję napisać kwerendę sql, aby uzyskać wszystkie informacje o koncie, w tym poziomy uprawnień. Ma to na celu audyt bezpieczeństwa. Chcemy zrzucić wszystkie te informacje w czytelny sposób, aby ułatwić porównywanie. Mój problem polega na tym, że istnieje lista mostków/linków dla uprawnień, więc istnieje wiele rekordów na użytkownika. Chcę uzyskać wyniki z wszystkimi uprawnieniami dla jednego użytkownika w jednym wierszu. Oto przykład:Pomoc dotycząca zapytań SQL z tabelą mostów

Table_User: 
UserId UserName 
1  John 
2  Joe 
3  James 

Table_UserPermissions: 
UserId PermissionId Rights 
1  10    1 
1  11    2 
1  12    3 
2  11    2 
2  12    3 
3  10    2 

PermissionID linki do tabeli z nazwą uprawnień i co robi. Prawo jest jak 1 = 2 = widzenia, modyfikować i itp

Co wrócę z podstawowej kwerendy dla użytkownika 1 jest:

UserId UserName PermissionId Rights 
1  John  10   1 
1  John  11   2 
1  John  12   3 

Co chciałbym coś takiego:

UserId UserName Permission1 Rights1 Permission2 Right2 Permission3 Right3 
1  John  10   1  11   2  12   3 

Idealnie chciałbym to dla wszystkich użytkowników. Najbliższą rzeczą, którą znalazłem jest funkcja Pivot w SQL Server 2005. http://geekswithblogs.net/lorint/archive/2006/08/04/87166.aspx Problem z tym, co mogę powiedzieć, to to, że muszę podać nazwę każdej kolumny dla każdego użytkownika i nie jestem pewien, jak uzyskać poziom praw. Z prawdziwymi danymi mam około 130 użytkowników i 40 różnych uprawnień.

Czy jest jeszcze inny sposób z usługą sql, że mogę to zrobić?

+0

I * wiem * Prawie dokładnie to pytanie na tej stronie widziałem co najmniej dwa razy. Ale nie mogę tego znaleźć. –

Odpowiedz

3

Można zrobić coś takiego:

select userid, username 
,  max(case when permissionid=10 then rights end) as permission10_rights 
,  max(case when permissionid=11 then rights end) as permission11_rights 
,  max(case when permissionid=12 then rights end) as permission12_rights 
from userpermissions 
group by userid, username; 

Trzeba wyraźnie dodać kolumnę podobny max (...) dla każdego permissionid.

+1

Zobacz także słowo kluczowe PIVOT dla serwera sql 2005 i późniejszych –

0

Można by utworzyć tymczasowy table_flatuserpermissions z:

UserID 
PermissionID1 
Rights1 
PermissionID2 
Rights2 
...etc to as many permission/right combinations as you need

zapisów Włożyć do tej tabeli z Table_user ze wszystkimi zgody & dziedzinach prawa zerowej.

rekordy update na tabeli z table_userpermissions - najpierw włożyć rekordu i ustawić PermissionID1 & Rights1, drugi rekord dla aktualizacji użytkownika PermissionsID2 & Rights2 itp

Następnie kwerendy tej tabeli, aby wygenerować raport.

Osobiście po prostu trzymam się kolumn UserId, UserName, PermissionID, Rights, które posiadasz.

Może zastąpić w pewnym tekście dla PermissionID i Rights zamiast wartości numerycznych.

Może posortować tabelę według PermissionID, User zamiast User, PermissionID, aby kontroler mógł sprawdzić użytkowników każdego typu uprawnień.

1

Krótka odpowiedź:

nr

Nie można dynamicznie dodawać kolumny w zapytaniu.

Pamiętaj, że SQL jest językiem opartym na zestawie. Wyszukujesz zestawy i łączysz zbiory razem.

To, co wykopujesz, jest listą rekurencyjną i wymaga, aby lista była nawleczona poziomo, a nie pionowo.

Możesz, sortuj, podrabiać go, korzystając z zestawu samodzielnych połączeń, ale aby to zrobić, musisz znać wszystkie możliwe uprawnienia, zanim napiszesz zapytanie ... co sugerowały inne propozycje.

Możesz także wycofać zestaw rekordów z powrotem do innego języka, a następnie powtórzyć go, aby wygenerować właściwe kolumny.

Coś jak:

SELECT Table_User.userID, userName, permissionid, rights 
FROM Table_User 
     LEFT JOIN Table_UserPermissions ON Table_User.userID =Table_UserPermissions.userID 
ORDER BY userName 

, a następnie wyświetlić wszystkie uprawnienia dla każdego użytkownika za pomocą coś jak (Python):

userID = recordset[0][0] 
userName = recordset[0][1] 
for row in recordset: 
    if userID != row[0]: 
     printUserPermissions(username, user_permissions) 
     user_permissions = [] 
     username = row[1] 
     userID = row[0] 

    user_permissions.append((row[2], row[3])) 

printUserPermissions(username, user_permissions) 
+0

Dzięki. Myślę, że również nie będzie działać z samym sql. Nie sumuje się wartości pól takich jak większość przykładów przestawnych i jest o wiele za dużo pól uprawnień, dla których mam pisać kolumny. Administrator ma ponad 120 uprawnień. Myślę, że będę musiał kodować to z C#. – MaxGeek

0

Jeśli jest to dopuszczalne, strategia Używałem zarówno dla zaprojektowanie i/lub wdrożenie, to zrzucenie zapytania niepodzielonego do Excela lub Access. Oba mają znacznie bardziej przyjazne interfejsy do przenoszenia danych, a dużo więcej osób czuje się komfortowo w tym środowisku.

Gdy masz już projekt, który ci się podoba, łatwiej jest pomyśleć o jego duplikowaniu w TSQL.

0

Wygląda na to, że funkcja przestawna została zaprojektowana dla sytuacji, w których można użyć funkcji agregującej na jednym z pól. Tak jak gdybym chciał wiedzieć, ile dochodu każdy sprzedawca wykonał dla firmy x. Mogłem podsumować pole cenowe ze stołu sprzedaży. Kupiłbym wtedy sprzedawcę i ile miałby on w sprzedaży. W przypadku uprawnień nie ma sensu sumowanie/liczenie/etc w górę pola permissionId lub pola Rights.

1

Jeśli używasz MySQL, proponuję użyć group_concat() jak poniżej.

select UserId, UserName, 
     group_concat(PermissionId) as PermIdList, 
     group_concat(Rights SEPARATOR ',') as RightsList 
from Table_user join Table_UserPermissions on 
    Table_User.UserId = Table_UserPermissions.UserId= 
GROUP BY Table_User.UserId 

byłby to powrót

UserId UserName PermIdList RightsList 
1  John  10,11,12 1,2,3 

Szybkie wyszukiwanie google dla 'mssql GROUP_CONCAT' ujawniła kilka różnych procedur przechowywanych (I), (II) dla MSSQL, że można osiągnąć to samo zachowanie.

0

Dla tego rodzaju transformacji danych należy wykonać zarówno dane UNPIVOT, jak i PIVOT. Jeśli znasz wartości, które chcesz przekształcić, możesz je zakodować za pomocą statycznego pliku przestawnego, w przeciwnym razie możesz użyć dynamicznego sql.

tworzyć tabele:

CREATE TABLE Table_User 
    ([UserId] int, [UserName] varchar(5)) 
; 

INSERT INTO Table_User 
    ([UserId], [UserName]) 
VALUES 
    (1, 'John'), 
    (2, 'Joe'), 
    (3, 'James') 
; 

CREATE TABLE Table_UserPermissions 
    ([UserId] int, [PermissionId] int, [Rights] int) 
; 

INSERT INTO Table_UserPermissions 
    ([UserId], [PermissionId], [Rights]) 
VALUES 
    (1, 10, 1), 
    (1, 11, 2), 
    (1, 12, 3), 
    (2, 11, 2), 
    (2, 12, 3), 
    (3, 10, 2) 
; 

Static PIVOT:

select * 
from 
(
    select userid, 
    username, 
    value, 
    col + '_'+ cast(rn as varchar(10)) col 
    from 
    (
    select u.userid, 
     u.username, 
     p.permissionid, 
     p.rights, 
     row_number() over(partition by u.userid 
         order by p.permissionid, p.rights) rn 
    from table_user u 
    left join Table_UserPermissions p 
     on u.userid = p.userid 
) src 
    unpivot 
    (
    value 
    for col in (permissionid, rights) 
) unpiv 
) src 
pivot 
(
    max(value) 
    for col in (permissionid_1, rights_1, 
       permissionid_2, rights_2, 
       permissionid_3, rights_3) 
) piv 
order by userid 

Zobacz SQL Fiddle with Demo

Dynamiczny PIVOT:

Jeśli masz nieznaną liczbę permissionid s oraz rights, a następnie można użyć dynamicznego SQL:

DECLARE 
    @query AS NVARCHAR(MAX), 
    @colsPivot as NVARCHAR(MAX) 

select @colsPivot = STUFF((SELECT ',' 
         + quotename(c.name +'_'+ cast(t.rn as varchar(10))) 
        from 
        (
         select row_number() over(partition by u.userid 
           order by p.permissionid, p.rights) rn 
         from table_user u 
         left join Table_UserPermissions p 
         on u.userid = p.userid 
        ) t 
        cross apply sys.columns as C 
        where C.object_id = object_id('Table_UserPermissions') and 
         C.name not in ('UserId') 
        group by c.name, t.rn 
        order by t.rn 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query 
    = 'select * 
    from 
    (
     select userid, 
     username, 
     value, 
     col + ''_''+ cast(rn as varchar(10)) col 
     from 
     (
     select u.userid, 
      u.username, 
      p.permissionid, 
      p.rights, 
      row_number() over(partition by u.userid 
          order by p.permissionid, p.rights) rn 
     from table_user u 
     left join Table_UserPermissions p 
      on u.userid = p.userid 
     ) src 
     unpivot 
     (
     value 
     for col in (permissionid, rights) 
     ) unpiv 
    ) x1 
    pivot 
    (
     max(value) 
     for col in ('+ @colspivot +') 
    ) p 
    order by userid' 

exec(@query) 

Zobacz SQL Fiddle with demo

wynik dla obu jest:

| USERID | USERNAME | PERMISSIONID_1 | RIGHTS_1 | PERMISSIONID_2 | RIGHTS_2 | PERMISSIONID_3 | RIGHTS_3 | 
--------------------------------------------------------------------------------------------------------- 
|  1 |  John |    10 |  1 |    11 |  2 |    12 |  3 | 
|  2 |  Joe |    11 |  2 |    12 |  3 |   (null) | (null) | 
|  3 | James |    10 |  2 |   (null) | (null) |   (null) | (null) | 
Powiązane problemy