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