6

我正在使用现有数据库并尝试编写一个 sql 查询来获取所有帐户信息,包括权限级别。这是为了安全审计。我们希望以一种可读的方式转储所有这些信息,以便于比较。我的问题是权限有一个桥/链接表,因此每个用户有多个记录。我想在一行上获得一个用户的所有权限的结果。这是一个例子:

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 链接到带有权限名称及其功能的表。权利就像 1 = 查看,2 = 修改等等。

我从用户 1 的基本查询中得到的是:

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

我想要这样的东西:

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

理想情况下,我希望所有用户都这样做。我发现的最接近的是 SQL Server 2005 中的 Pivot 函数。 http://geekswithblogs.net/lorint/archive/2006/08/04/87166.aspx 据我所知,这个问题是我需要为每个用户命名每一列,我不确定如何获得权限级别。使用真实数据,我有大约 130 个用户和 40 种不同的权限。

是否有另一种仅使用 sql 的方法可以做到这一点?

4

8 回答 8

3

你可以这样做:

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;

您必须为每个权限 ID 显式添加类似的 max(...) 列。

于 2008-11-18T17:38:49.887 回答
2

如果你在哪里使用 MySQL,我建议你使用group_concat()如下所示。

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

这将返回

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

对“mssql group_concat”的快速谷歌搜索显示了可以实现相同行为的 MSSQL 的几个不同存储过程 ( I )、( II )。

于 2008-11-19T01:33:50.973 回答
1

简短的回答:

不。

您不能在查询中动态添加列。

请记住,SQL 是一种基于集合的语言。您查询集合并将集合连接在一起。

您要挖掘的是一个递归列表,并要求该列表水平而不是垂直地串在一起。

您可以使用一组自连接来伪造它,但为了做到这一点,您必须在编写查询之前了解所有可能的权限......这是其他建议所提出的。

您还可以将记录集拉回另一种语言,然后对其进行迭代以生成正确的列。

就像是:

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

然后使用(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)
于 2008-11-18T17:52:58.407 回答
0

如果可以接受,我在设计和/或实施方面使用的策略是将查询转储到 Excel 或 Access 中。两者都有更友好的用户界面来透视数据,并且更多的人在这种环境中感到舒适。

一旦有了自己喜欢的设计,就更容易考虑如何在 TSQL 中复制它。

于 2008-11-18T18:30:26.290 回答
0

似乎枢轴函数是为您可以在其中一个字段上使用聚合函数的情况而设计的。就像我想知道每个销售人员为 x 公司赚了多少收入一样。我可以总结销售表中的价格字段。然后我会得到销售人​​员以及他们有多少销售收入。对于权限,尽管对permissionId 字段或Rights 字段进行求和/计数/等是没有意义的。

于 2008-11-18T18:51:47.370 回答
0

您可能希望查看以下有关在 SQL 中创建交叉表查询的示例:

http://www.databasejournal.com/features/mssql/article.php/3521101/Cross-Tab-reports-in-SQL-Server-2005.htm

SQL Server 2005 中似乎包含了一些新操作,称为 PIVOT 和 UNPIVOT

于 2008-11-18T19:02:54.693 回答
0

您可以创建一个临时 table_flatuserpermissions :

用户身份
权限 ID1
权利1
权限 ID2
权利2
...等您需要的尽可能多的权限/权利组合

从 Table_user 将记录插入此表,所有权限和权限字段均为空。

从 table_userpermissions 更新此表上的记录 - 第一条记录插入并设置 PermissionID1 和 Rights1,第二条记录用于用户更新 PermissionsID2 和 Rights2 等。

然后查询此表以生成报告。

就个人而言,我会坚持使用您现在拥有的 UserId、UserName、PermissionID、Rights 列。

也许用一些文本代替 PermissionID 和 Rights 而不是数值。

也许按 PermissionID、User 而不是 User、PermissionID 对表进行排序,以便审核员可以检查每个权限类型的用户。

于 2008-11-18T17:41:12.440 回答
0

对于这种类型的数据转换,您将需要先执行数据UNPIVOT,然后再执行PIVOT数据。如果您知道要转换的值,则可以使用静态数据透视对查询进行硬编码,否则可以使用动态 sql。

创建表:

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

静态枢轴:

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

请参阅带有演示的 SQL Fiddle

动态枢轴:

如果您有未知数量的permissionids 和rights,那么您可以使用动态 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)

请参阅带有演示的 SQL Fiddle

两者的结果是:

| 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) |
于 2012-12-21T15:09:49.980 回答