Sql 从对表创建输出矩阵

Sql 从对表创建输出矩阵,sql,Sql,我有一个角色与权限表,如下所示: role | permission r1 | p1 r2 | p1 r2 | p2 r3 | p1 r3 | p2 r3 | p3 我想要的是一个输出表,其中列是(角色,然后是每个权限)。如果权限/角色对存在于表中,我需要1,如果不存在,我需要0 以下是输出: role | p1 | p2 | p3 r1 | 1 | 0 | 0 r2 | 1 | 1 | 0 r3 | 1 | 1 | 1 这很容易,但关

我有一个角色与权限表,如下所示:

role | permission    
r1   | p1
r2   | p1
r2   | p2
r3   | p1
r3   | p2
r3   | p3
我想要的是一个输出表,其中列是(角色,然后是每个权限)。如果权限/角色对存在于表中,我需要1,如果不存在,我需要0

以下是输出:

role | p1 | p2 | p3
r1   | 1  | 0  | 0
r2   | 1  | 1  | 0
r3   | 1  | 1  | 1
这很容易,但关键是…角色或权限都不是固定长度的,可以随时添加新的,因此我需要考虑这一点。


由于SQL的性质,我认为这是不可能的,但我想我会问一下。

您没有指定您使用的是什么RDBMS-因此这里是MySQL和SQL Server的解决方案

MySQL:

这是一个
PIVOT
,但MySQL没有
PIVOT
函数,因此需要使用聚合函数和
CASE
语句复制它

静态版本-是您事先知道所有值的地方:

select role,
  sum(case when permission = 'p1' then 1 else 0 end) p1,
  sum(case when permission = 'p2' then 1 else 0 end) p2,
  sum(case when permission = 'p3' then 1 else 0 end) p3
from yourtable
group by role;

如果您事先不知道要转到列的值,则可以使用准备好的语句:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'sum(case when permission = ''',
      permission,
      ''' then 1 else 0 end) AS ',
      permission
    )
  ) INTO @sql
FROM yourtable;

SET @sql = CONCAT('SELECT role, ', @sql, ' 
                  FROM yourtable 
                   GROUP BY role');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SQL Server:

sql server中有一个
PIVOT
函数,您可以硬编码值,也可以使用动态sql

静态版本:

select *
from 
(
  select role, permission
  from yourtable
) src
pivot
(
  count(permission)
  for permission in ([p1], [p2], [p3])
) piv;
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(permission) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT role, ' + @cols + ' from 
             (
                select role, permission
                from yourtable
            ) x
            pivot 
            (
                count(permission)
                for permission in (' + @cols + ')
            ) p '

execute(@query)

动态版本:

select *
from 
(
  select role, permission
  from yourtable
) src
pivot
(
  count(permission)
  for permission in ([p1], [p2], [p3])
) piv;
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(permission) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT role, ' + @cols + ' from 
             (
                select role, permission
                from yourtable
            ) x
            pivot 
            (
                count(permission)
                for permission in (' + @cols + ')
            ) p '

execute(@query)

所有版本的结果是:

| ROLE | P1 | P2 | P3 |
-----------------------
|   r1 |  1 |  0 |  0 |
|   r2 |  1 |  1 |  0 |
|   r3 |  1 |  1 |  1 |

请添加给定数据的预期输出。哪个数据库?这被称为“数据透视表”,它是如何完成的,正如techdo已经问过的,取决于所使用的数据库系统。这是一个有效的问题,但可能是重复的