How to convert rows to new columns in m to n relation ship table?

依然范特西╮ 提交于 2020-01-05 04:17:35

问题


I need some help with a problem.

I am working on a microsoft database with SQL and I have a Table that looks similar to this one:

|*Name*|*Permissions*|
|App1  |Permission 1 |
|App1  |Permission 2 |
|App1  |Permission 3 |
|App2  |Permission 1 |
|App2  |Permission 2 |
|App2  |Permission 3 |

So it is an m to n relation ship, as there are multiple permissions assigned to an app but there are also multiple apps using the same permission.

I have already tried something like joining the table with itself using distinct like this:

select distinct apps1.name, apps2.permissions from Apps apps1
join Apps apps2
where apps2.name IN
(SELECT distinct name from Apps);

but it doesnt get me the result I am looking for.

I would like to get a result that looks like this:

|*Name*|*Permission1*|*Permission2*|*Permission3*|
|App1  |Permission 1 |Permission 2 |Permission 3 |
|App2  |Permission 1 |Permission 2 |Permission 3 |

It is possible, that apps have got a different amount of permissions, but if it is so, it would be okay if these empty columns are filled with NULL values.

I hope you can help me. If any further information is needed, just write me. As I am new to StackOverflow I am not a professional in writing down the question.


回答1:


If you have a maximum number of permissions that you care about (say three), you can just use conditional aggregation (or pivot):

select a.name,
       max(case when seqnum = 1 then a.permission end) as permission_1,
       max(case when seqnum = 2 then a.permission end) as permission_2,
       max(case when seqnum = 3 then a.permission end) as permission_3
from (select a.*,
             row_number() over (partition by a.name order by a.name) as seqnum
      from apps a
     ) a
group by a.name;

If you don't know how many columns you want returned, then you need to use dynamic SQL and the query is a bit more complicated.




回答2:


You can use the PIVOT operator for this. An example is given below.

CREATE TABLE #Permission
(
 Name       VARCHAR(10)
,Permission VARCHAR(25)
)

INSERT INTO #Permission (Name, Permission) VALUES
('App1', 'Permission 1')
,('App1', 'Permission 2')
,('App1', 'Permission 3')
,('App2', 'Permission 1')
,('App2', 'Permission 2')
,('App2', 'Permission 3')
,('App3', 'Permission 2');


SELECT * 
FROM
    (
    SELECT Name, Permission FROM #Permission
    ) AS A
PIVOT
    (
    MAX(Permission)
    FOR Permission IN ([Permission 1], [Permission 2], [Permission 3])
    ) AS PivotTable

DROP TABLE #Permission;

If you have n number of permissions then you may have to use dynamic pivoting.




回答3:


You can use PIVOT for this kind of query:

A mockup-scenario to simulate your issue

DECLARE @mockupTable TABLE([Name] VARCHAR(100),[Permissions] VARCHAR(100));
INSERT INTO @mockupTable VALUES
 ('App1','Permission 1')
,('App1','Permission 2')
,('App1','Permission 3')
,('App2','Permission 1')
,('App2','Permission 2')
,('App2','Permission 3');

--the query

SELECT p.*
FROM
(
    SELECT t.*
          ,CONCAT('Permission',ROW_NUMBER() OVER(PARTITION BY t.[Name] ORDER BY t.[Permissions])) AS ColumnName
    FROM @mockupTable t
) tbl
PIVOT
(
    MAX(tbl.[Permissions]) 
    FOR tbl.ColumnName 
    IN(Permission1,Permission2,Permission3,Permission4 /*add as many as you need*/)
) p;

The idea in short:

With CONCAT and ROW_NUMBER we can create a value, which we can later use as the pivot's column name.




回答4:


You can also try this USING CTE

;with cte as (
SELECT *
        ,ROW_NUMBER() over(partition by Name order by Permissions ) rn
FROM YourTable
) 

select      Name
            ,MAX(case   when rn=1 then Permissions   end) Permission1
            ,MAX(case   WHEN rn=2 then Permissions  end) Permission2
            ,MAX(case   WHEN rn=3 then Permissions  end) Permission3
FROM cte 
group by Name


来源:https://stackoverflow.com/questions/58183730/how-to-convert-rows-to-new-columns-in-m-to-n-relation-ship-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!