MS SQL Pivot Another Table Multiple Times

孤者浪人 提交于 2021-02-11 12:32:06

问题


I have a database with the following structure

ID   Name
1     John
2     Doe
3     Dave
4     Smith

Another table holds employee relatives

ID EmpID RelativeType Name
1  1      Son         x
2  1      Daughter    y
3  1      Wife        a
4  1      Friend      b
5  1      Father      c
6  1      Friend      e

Childs can be fixed upto maximum of 8 and friends can be maximum of 3

I was able to make a pivot query below to bring childs, but unable to pivot again to fetch 3 friends, father etc.

This is my query:

    select *
from 
(
  select e.ID, e.FirstName,
  CASE WHEN es.RelativeType = 'Son' or es.RelativeType = 'Daughter' THEN es.FirstName END as Child, CASE WHEN es.RelativeType = 'Son' or es.RelativeType = 'Daughter' THEN CONCAT('Child ',ROW_NUMBER() OVER (ORDER BY e.ID)) END as Relation
  from Employee e
  left join EmployeeRelatives es
    on e.ID = es.EmpID
  group by 
 e.ID, e.FirstName,es.RelativeID,es.FirstName
) x
pivot
(
  max(Child)
  for Relation in([Child 1],[Child 2],[Child 3], [Child 4], [Child 5], [Child 6], [Child 7], [Child 8])
) as p1

The above query returns the following result.

EmpID , Name, Child 1, Child 2,Child 3, Child 4, Child 5, Child 6
 1      John   x        y       NULL    NULL     NULL     NULL

When I make multiple pivots it returns multiple rows, which is not required. I need to amend the above query to bring the desired result

The Required Resultset is as follows

EmpID , Name, Child 1, Child 2, Child 3, Child 4, Wife, Friend 1, Friend 2, Friend 3, Father
 1      John   x        y         NULL    NULL      a      b        e          NULL       c

I am using MS SQL 2014.


回答1:


You may try this out and I hope this can help you :) Good Luck!! :)

WITH Children AS
(
    SELECT e.EmpID, e.FirstName EmpName, er.FirstName RelName,
            'Child' + CONVERT(NVARCHAR(2), ROW_NUMBER() OVER (PARTITION BY er.EmpID ORDER BY er.RelativeID)) AS 'Relation'
    FROM Employee e
    LEFT JOIN EmployeeRelatives er ON e.EmpID = er.EmpID
    WHERE er.RelativeType IN ('Son', 'Daughter')
),
ChildInRow AS
(
    SELECT *
    FROM Children
    PIVOT
    (
      MAX(RelName)
      FOR Relation in([Child1],[Child2],[Child3], [Child4], [Child5], [Child6], [Child7], [Child8])
    ) AS p1
),
Friends AS
(
    SELECT e.EmpID, e.FirstName EmpName, er.FirstName RelName,
            'Friend' + CONVERT(NVARCHAR(2), ROW_NUMBER() OVER (PARTITION BY er.EmpID ORDER BY er.RelativeID)) AS 'Relation'
    FROM Employee e
    LEFT JOIN EmployeeRelatives er ON e.EmpID = er.EmpID
    WHERE er.RelativeType = 'Friend'
),
FriendsInRow AS
(
    SELECT *
    FROM Friends
    PIVOT
    (
      MAX(RelName)
      FOR Relation in([Friend1],[Friend2],[Friend3])
    ) AS p1
),
AllWife AS
(
    SELECT e.EmpID, e.FirstName EmpName, er.FirstName RelName, 'Wife' AS 'Relation',
            ROW_NUMBER() OVER (PARTITION BY er.EmpID ORDER BY er.RelativeID) wife_row_num
    FROM Employee e
    LEFT JOIN EmployeeRelatives er ON e.EmpID = er.EmpID
    WHERE er.RelativeType = 'Wife'
),
WifeInRow AS
(
    SELECT * FROM AllWife WHERE wife_row_num = 1
),
AllFather AS
(
    SELECT e.EmpID, e.FirstName EmpName, er.FirstName RelName, 'Father' AS 'Relation',
            ROW_NUMBER() OVER (PARTITION BY er.EmpID ORDER BY er.RelativeID) father_row_num
    FROM Employee e
    LEFT JOIN EmployeeRelatives er ON e.EmpID = er.EmpID
    WHERE er.RelativeType = 'Father'
),
FatherInRow AS
(
    SELECT * FROM AllFather WHERE father_row_num = 1
)
SELECT e.EmpID, e.FirstName,
        ISNULL(Child1, '') Child1, ISNULL(Child2, '') Child2, ISNULL(Child3, '') Child3, ISNULL(Child4, '') Child4, ISNULL(Child5, '') Child5, ISNULL(Child6, '') Child6, ISNULL(Child7, '') Child7, ISNULL(Child8, '') Child8,
        ISNULL(w.RelName, '') Wife,
        ISNULL(Friend1, '') Friend1, ISNULL(Friend2, '') Friend2, ISNULL(Friend3, '') Friend3,
        ISNULL(fa.RelName, '') Father
FROM Employee e
FULL OUTER JOIN ChildInRow c ON e.EmpID = c.EmpID
FULL OUTER JOIN FriendsInRow f ON e.EmpID = f.EmpID
FULL OUTER JOIN WifeInRow w ON e.EmpID = w.EmpID
FULL OUTER JOIN FatherInRow fa ON e.EmpID = fa.EmpID

And the result should be something like:




回答2:


I've used what's known as a "CROSS PIVOT" here.

Like i said, this isn't pretty; you should really be doing this in your presentation layer. This solution is not going to be scalable, and probably a pain to maintain. Anyway, here goes:

CREATE TABLE #Employee (ID int, [Name] varchar(10));

INSERT INTO #Employee
VALUES(1,'John'),
      (2,'Doe'),
      (3,'Dave'),
      (4,'Smith');

CREATE TABLE #Relative (ID int, EmpID int, RelativeType varchar(10), [Name] char(1)); 
INSERT INTO #Relative
VALUES(1,1,'Son','x'),
      (2,1,'Daughter','y'),
      (3,1,'Wife','a'),
      (4,1,'Friend','b'),
      (5,1,'Father','c'),
      (6,1,'Friend','e');

WITH RNs AS (
    SELECT *,
           CASE RelativeType WHEN 'Son' THEN 'Child'
                             WHEN 'Daughter' THEN 'Child'
                             WHEN 'Mother' THEN 'Parent'
                             WHEN 'Father' THEN 'Parent'
                             WHEN 'Wife' THEN 'Spouse'
                             WHEN 'Husband' THEN 'Spouse'
                             ELSE RelativeType END AS Relation,
           ROW_NUMBER() OVER (PARTITION BY EmpID,
                                           CASE RelativeType WHEN 'Son' THEN 'Child'
                                                             WHEN 'Daughter' THEN 'Child'
                                                             WHEN 'Mother' THEN 'Parent'
                                                             WHEN 'Father' THEN 'Parent'
                                                             WHEN 'Wife' THEN 'Spouse'
                                                             WHEN 'Husband' THEN 'Spouse'
                                                             ELSE RelativeType END
                              ORDER BY ID ASC) RN
    FROM #Relative R)

SELECT E.ID AS EmpID,
       E.[Name],
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 1 THEN R.[Name] END) AS Child1,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 2 THEN R.[Name] END) AS Child2,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 3 THEN R.[Name] END) AS Child3,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 4 THEN R.[Name] END) AS Child4,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 5 THEN R.[Name] END) AS Child5,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 6 THEN R.[Name] END) AS Child6,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 7 THEN R.[Name] END) AS Child7,
       MAX(CASE WHEN R.Relation = 'Child' AND RN = 8 THEN R.[Name] END) AS Child8,
       MAX(CASE WHEN R.Relation = 'Spouse' AND RN = 1 THEN R.[Name] END) AS Spouse,
       MAX(CASE WHEN R.Relation = 'Friend' AND RN = 1 THEN R.[Name] END) AS Friend1,
       MAX(CASE WHEN R.Relation = 'Friend' AND RN = 2 THEN R.[Name] END) AS Friend2,
       MAX(CASE WHEN R.Relation = 'Friend' AND RN = 3 THEN R.[Name] END) AS Friend3
       --You get the idea
FROM #Employee E
     JOIN RNs R ON E.ID = R.EmpID
GROUP BY E.ID,
         E.[Name];

GO
DROP TABLE #Employee;
DROP TABLE #Relative;


来源:https://stackoverflow.com/questions/49750475/ms-sql-pivot-another-table-multiple-times

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