问题
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