Sql 联接表并全部联合/透视/取消Pivot?
我在数据库中有四个表,如下所示: 表1:员工详细信息Sql 联接表并全部联合/透视/取消Pivot?,sql,sql-server,sql-server-2008,tsql,join,Sql,Sql Server,Sql Server 2008,Tsql,Join,我在数据库中有四个表,如下所示: 表1:员工详细信息 ----------------------------------------------------------------------- | Employee ID | Name | Department |DateofJoining | ----------------------------------------------------------------------- | | |
-----------------------------------------------------------------------
| Employee ID | Name | Department |DateofJoining |
-----------------------------------------------------------------------
| | | | |
| e1 | name1 | d1 | date1 |
| e2 | name2 | d2 | date2 |
| e3 | name3 | d3 | date3 |
-----------------------------------------------------------------------
-----------------------------------------------------------------------
| EmployeeID | CertificationID | Name |
-----------------------------------------------------------------------
| | | |
| e1 | c1 | cname1 |
| e1 | c2 | cname2 |
| e2 | c3 | cname3 |
-----------------------------------------------------------------------
----------------------------------------------------------------------------
| EmployeeId | TotalExp | Qualification | Specialization |
----------------------------------------------------------------------------
| | | | |
| e1 | 1 | q1 | abc |
| e2 | 2 | q2 | xyz |
----------------------------------------------------------------------------
表2:员工技能集
----------------------------------------------------------------------------
| EmployeeID | SkillId | SkillName | SkillExperience | SkillRating |
----------------------------------------------------------------------------
| | | | | |
| e1 | s1 | skill1 | 11| 11|
| e1 | s2 | skill2 | 12| 12|
| e1 | s3 | skill3 | 13| 13|
| e2 | s1 | skill1 | 21| 21|
| e2 | s2 | skill2 | 22| 22|
| e2 | s3 | skill3 | 23| 23|
----------------------------------------------------------------------------
表3:员工认证
-----------------------------------------------------------------------
| Employee ID | Name | Department |DateofJoining |
-----------------------------------------------------------------------
| | | | |
| e1 | name1 | d1 | date1 |
| e2 | name2 | d2 | date2 |
| e3 | name3 | d3 | date3 |
-----------------------------------------------------------------------
-----------------------------------------------------------------------
| EmployeeID | CertificationID | Name |
-----------------------------------------------------------------------
| | | |
| e1 | c1 | cname1 |
| e1 | c2 | cname2 |
| e2 | c3 | cname3 |
-----------------------------------------------------------------------
----------------------------------------------------------------------------
| EmployeeId | TotalExp | Qualification | Specialization |
----------------------------------------------------------------------------
| | | | |
| e1 | 1 | q1 | abc |
| e2 | 2 | q2 | xyz |
----------------------------------------------------------------------------
表4:其他详细信息
-----------------------------------------------------------------------
| Employee ID | Name | Department |DateofJoining |
-----------------------------------------------------------------------
| | | | |
| e1 | name1 | d1 | date1 |
| e2 | name2 | d2 | date2 |
| e3 | name3 | d3 | date3 |
-----------------------------------------------------------------------
-----------------------------------------------------------------------
| EmployeeID | CertificationID | Name |
-----------------------------------------------------------------------
| | | |
| e1 | c1 | cname1 |
| e1 | c2 | cname2 |
| e2 | c3 | cname3 |
-----------------------------------------------------------------------
----------------------------------------------------------------------------
| EmployeeId | TotalExp | Qualification | Specialization |
----------------------------------------------------------------------------
| | | | |
| e1 | 1 | q1 | abc |
| e2 | 2 | q2 | xyz |
----------------------------------------------------------------------------
现在,必须查询上述四个表才能获得如下输出:
+------------+-------+-------------+---------------+---------+----------------+----------------+------------+----------------+--------+--------------+------------------+
| EmployeeID | Name | Department | Qualification | Tot_Exp | Specialization | Certifications | Skill1_Exp | Skill1_Rating | ……………… | Skill100_Exp | Skill100_Rating |
+------------+-------+-------------+---------------+---------+----------------+----------------+------------+----------------+--------+--------------+------------------+
| | | | | | | | | | | | |
| e1 | name1 | d1 | q1 | 1 | spec1 | c1,c2 | 11 | 11 | ……………. | ………………… | ……………………… |
| e2 | name2 | d2 | q2 | 2 | spec2 | c3 | 21 | 21 | ……………. | ………………… | ……………………… |
+------------+-------+-------------+---------------+---------+----------------+----------------+------------+----------------+--------+--------------+------------------+
到目前为止,我已经能够对表2-Employee_SkillSet执行一个查询(使用动态SQL),如下所示:
----------------------------------------------------------------------------
| EmpId | S1_Exp | S1_Rating | S2_Exp | S2_Rating | S3_Exp | S3_Rating |....
----------------------------------------------------------------------------
| | | | | | | |
| e1 | 11 | 11 | 12 | 12 | 13 | 13 |....
| e2 | 21 | 21 | 22 | 22 | 23 | 23 |....
| e3 | 31 | 31 | 32 | 32 | 33 | 33 |....
----------------------------------------------------------------------------
P.S. S is for Skill which I abbreviated over here to conserve space
我的问题是,如何将其他三个表按行连接到此表,以获得所需的输出
我可能应该指出,我对连接、透视/取消透视、交叉应用以及两者之间的一切都很陌生,所以即使答案非常简单,我似乎也无法理解
编辑
创建脚本:
CREATE TABLE Employee_Details (
[Employee ID] nvarchar(2),
[Name] nvarchar(10),
Department nvarchar(2),
DateofJoining nvarchar(5)
)
INSERT INTO Employee_Details VALUES
('e1', 'name1', 'd1', 'date1'),
('e2', 'name2', 'd2', 'date2'),
('e3', 'name3', 'd3', 'date3')
CREATE TABLE Employee_SkillSet (
EmployeeID nvarchar(2),
SkillId nvarchar(2),
SkillName nvarchar(10),
SkillExperience int,
SkillRating int
)
INSERT INTO Employee_SkillSet VALUES
('e1', 's1', 'skill1', 11, 11),
('e1', 's2', 'skill2', 12, 12),
('e1', 's3', 'skill3', 13, 13),
('e2', 's1', 'skill1', 21, 21),
('e2', 's2', 'skill2', 22, 22),
('e2', 's3', 'skill3', 23, 23)
CREATE TABLE Employee_Certifications (
EmployeeID nvarchar(2),
CertificationID nvarchar(2),
[Name] nvarchar(10)
)
INSERT INTO Employee_Certifications VALUES
('e1', 'c1', 'cname1'),
('e1', 'c2', 'cname2'),
('e2', 'c3', 'cname3')
CREATE TABLE Other_Details (
EmployeeId nvarchar(2),
TotalExp int,
Qualification nvarchar(2),
Specialization nvarchar(100)
)
INSERT INTO Other_Details VALUES
('e1', 1, 'q1', 'abc'),
('e2', 2, 'q2', 'xyz')
创建脚本:您可以使用以下内容,而不是使用动态SQL获取技能:
SELECT ed.EmployeeID AS EmpID,
ss1.SkillExperience AS S1_Exp,
ss1.SkillRating AS S1_Rating,
ss2.SkillExperience AS S2_Exp,
ss2.SkillRating AS S2_Rating,
ss3.SkillExperience AS S3_Exp,
ss3.SkillRating AS S3_Rating
FROM Employee_Details ed
INNER JOIN Employee_SkillSet ss1 ON ed.EmployeeID = ss1.EmployeeID AND ss1.SkillName = 'skill1'
INNER JOIN Employee_SkillSet ss2 ON ed.EmployeeID = ss2.EmployeeID AND ss2.SkillName = 'skill2'
INNER JOIN Employee_SkillSet ss3 ON ed.EmployeeID = ss3.EmployeeID AND ss3.SkillName = 'skill2'
现在来完成它
WITH Certifications AS
(
SELECT EmployeeId
,STUFF((SELECT ', ' + CAST(Name AS VARCHAR(10)) [text()]
FROM Employee_Certifications
WHERE EmployeeId = c.EmployeeId
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') Certifications
FROM Employee_Certifications c
GROUP BY EmployeeId
)
,Skills AS
(
SELECT ed.EmployeeID AS EmpID,
ss1.SkillExperience AS S1_Exp,
ss1.SkillRating AS S1_Rating,
ss2.SkillExperience AS S2_Exp,
ss2.SkillRating AS S2_Rating,
ss3.SkillExperience AS S3_Exp,
ss3.SkillRating AS S3_Rating
FROM Employee_Details ed
INNER JOIN Employee_SkillSet ss1 ON ed.EmployeeID = ss1.EmployeeID AND ss1.SkillName = 'skill1'
INNER JOIN Employee_SkillSet ss2 ON ed.EmployeeID = ss2.EmployeeID AND ss2.SkillName = 'skill2'
INNER JOIN Employee_SkillSet ss3 ON ed.EmployeeID = ss3.EmployeeID AND ss3.SkillName = 'skill2'
)
SELECT ed.EmployeeID,
ed.Name,
ed.Department,
od.Qualification,
od.TotalExp,
od.Specialization,
c.Certifications,
s.S1_Exp,
s.S1_Rating,
s.S2_Exp,
s.S2_Rating,
s.S3_Exp,
s.S3_Rating
FROM Employee_Details ed
LEFT JOIN Other_Details od ON od.EmployeeId = ed.EmployeeId
LEFT JOIN Certifications c ON c.EmployeeID = ed.EmployeeID
LEFT JOIN Skills s ON s.EmpID = ed.EmployeeID
您可以使用以下方法,而不是使用动态SQL获取技能:
SELECT ed.EmployeeID AS EmpID,
ss1.SkillExperience AS S1_Exp,
ss1.SkillRating AS S1_Rating,
ss2.SkillExperience AS S2_Exp,
ss2.SkillRating AS S2_Rating,
ss3.SkillExperience AS S3_Exp,
ss3.SkillRating AS S3_Rating
FROM Employee_Details ed
INNER JOIN Employee_SkillSet ss1 ON ed.EmployeeID = ss1.EmployeeID AND ss1.SkillName = 'skill1'
INNER JOIN Employee_SkillSet ss2 ON ed.EmployeeID = ss2.EmployeeID AND ss2.SkillName = 'skill2'
INNER JOIN Employee_SkillSet ss3 ON ed.EmployeeID = ss3.EmployeeID AND ss3.SkillName = 'skill2'
现在来完成它
WITH Certifications AS
(
SELECT EmployeeId
,STUFF((SELECT ', ' + CAST(Name AS VARCHAR(10)) [text()]
FROM Employee_Certifications
WHERE EmployeeId = c.EmployeeId
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') Certifications
FROM Employee_Certifications c
GROUP BY EmployeeId
)
,Skills AS
(
SELECT ed.EmployeeID AS EmpID,
ss1.SkillExperience AS S1_Exp,
ss1.SkillRating AS S1_Rating,
ss2.SkillExperience AS S2_Exp,
ss2.SkillRating AS S2_Rating,
ss3.SkillExperience AS S3_Exp,
ss3.SkillRating AS S3_Rating
FROM Employee_Details ed
INNER JOIN Employee_SkillSet ss1 ON ed.EmployeeID = ss1.EmployeeID AND ss1.SkillName = 'skill1'
INNER JOIN Employee_SkillSet ss2 ON ed.EmployeeID = ss2.EmployeeID AND ss2.SkillName = 'skill2'
INNER JOIN Employee_SkillSet ss3 ON ed.EmployeeID = ss3.EmployeeID AND ss3.SkillName = 'skill2'
)
SELECT ed.EmployeeID,
ed.Name,
ed.Department,
od.Qualification,
od.TotalExp,
od.Specialization,
c.Certifications,
s.S1_Exp,
s.S1_Rating,
s.S2_Exp,
s.S2_Rating,
s.S3_Exp,
s.S3_Rating
FROM Employee_Details ed
LEFT JOIN Other_Details od ON od.EmployeeId = ed.EmployeeId
LEFT JOIN Certifications c ON c.EmployeeID = ed.EmployeeID
LEFT JOIN Skills s ON s.EmpID = ed.EmployeeID
您可以使用:
- 用于XML路径(“”)获取逗号分隔的值
- 动态SQL,所以如果有新技能出现,您无需更改查询
- 旋转以将行转换为列
DECLARE @col nvarchar(max),
@sql nvarchar(max)
SELECT @col = (
SELECT DISTINCT ','+QUOTENAME(SkillName + STUFF([name],1,5,'_'))
FROM Employee_SkillSet es
CROSS JOIN sys.columns sc
WHERE sc.[object_id] = OBJECT_ID(N'Employee_SkillSet')
AND sc.column_id > 3
FOR XML PATH('')
)
--That will generate the string:
--,[skill1_Experience],[skill1_Rating],[skill2_Experience],[skill2_Rating]...[skillN_Experience],[skillN_Rating]
SELECT @sql= N'
SELECT ed.EmployeeID,
ed.[Name],
ed.Department,
STUFF((
SELECT '',''+Qualification
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Qualification,
STUFF((
SELECT '',''+CAST(TotalExp as nvarchar(10))
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as TotalExp,
STUFF((
SELECT '',''+Specialization
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Specialization,
STUFF((
SELECT '',''+CertificationID
FROM Employee_Certifications
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Certification'+@col+'
FROM Employee_Details ed
LEFT JOIN (
SELECT *
FROM (
SELECT EmployeeID,
SkillName + STUFF(Skills,1,5,''_'') as [Columns],
[Values]
FROM (
SELECT *
FROM Employee_SkillSet
) as es
UNPIVOT (
[Values] FOR Skills IN (SkillExperience,SkillRating)
) unp
) as s
PIVOT (
MAX([Values]) FOR [Columns] IN ('+STUFF(@col,1,1,'')+')
) pvt
) as f
ON f.EmployeeID = ed.EmployeeID'
EXEC sp_executesql @sql
输出:
EmployeeID Name Department Qualification TotalExp Specialization Certification skill1_Experience skill1_Rating skill2_Experience skill2_Rating skill3_Experience skill3_Rating
e1 name1 d1 q1 1 abc c1,c2 11 11 12 12 13 13
e2 name2 d2 q2 2 xyz c3 21 21 22 22 23 23
e3 name3 d3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
注意:我在UNPIVOT部分使用SkillExperience,SkillRating
,如果有更多的技能属性,那么您可以使用另一个变量,如@col
来传递逗号分隔的值。您可以使用:
- 用于XML路径(“”)获取逗号分隔的值
- 动态SQL,所以如果有新技能出现,您无需更改查询
- 旋转以将行转换为列
DECLARE @col nvarchar(max),
@sql nvarchar(max)
SELECT @col = (
SELECT DISTINCT ','+QUOTENAME(SkillName + STUFF([name],1,5,'_'))
FROM Employee_SkillSet es
CROSS JOIN sys.columns sc
WHERE sc.[object_id] = OBJECT_ID(N'Employee_SkillSet')
AND sc.column_id > 3
FOR XML PATH('')
)
--That will generate the string:
--,[skill1_Experience],[skill1_Rating],[skill2_Experience],[skill2_Rating]...[skillN_Experience],[skillN_Rating]
SELECT @sql= N'
SELECT ed.EmployeeID,
ed.[Name],
ed.Department,
STUFF((
SELECT '',''+Qualification
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Qualification,
STUFF((
SELECT '',''+CAST(TotalExp as nvarchar(10))
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as TotalExp,
STUFF((
SELECT '',''+Specialization
FROM Other_Details
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Specialization,
STUFF((
SELECT '',''+CertificationID
FROM Employee_Certifications
WHERE ed.EmployeeID = EmployeeID
FOR XML PATH('''')
),1,1,'''') as Certification'+@col+'
FROM Employee_Details ed
LEFT JOIN (
SELECT *
FROM (
SELECT EmployeeID,
SkillName + STUFF(Skills,1,5,''_'') as [Columns],
[Values]
FROM (
SELECT *
FROM Employee_SkillSet
) as es
UNPIVOT (
[Values] FOR Skills IN (SkillExperience,SkillRating)
) unp
) as s
PIVOT (
MAX([Values]) FOR [Columns] IN ('+STUFF(@col,1,1,'')+')
) pvt
) as f
ON f.EmployeeID = ed.EmployeeID'
EXEC sp_executesql @sql
输出:
EmployeeID Name Department Qualification TotalExp Specialization Certification skill1_Experience skill1_Rating skill2_Experience skill2_Rating skill3_Experience skill3_Rating
e1 name1 d1 q1 1 abc c1,c2 11 11 12 12 13 13
e2 name2 d2 q2 2 xyz c3 21 21 22 22 23 23
e3 name3 d3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
注意:我在UNPIVOT部分使用了
SkillExperience,SkillRating
,如果有更多的技能属性,那么你可以使用另一个变量,比如@col
来传递逗号分隔的值。这不就是empID上的连接吗?您可能只需要一个类似STUFF FOR XML PATH(“”)的语句来连接列(例如,证书)。是的,它是EmpId上的连接。我搞不清楚的是如何透视结果表,使与一个EmpID对应的所有数据都在一行中,这不只是EmpID上的一个连接吗?您可能只需要一个类似STUFF FOR XML PATH(“”)的语句来连接列(例如,证书)。是的,它是EmpId上的连接。我搞不清楚的是如何透视结果表,以便与一个EmpID对应的所有数据都在一行中。我之所以使用动态sql,是因为这些技能超过100项。为所有100个技能ID显式添加数据是不行的。我之所以使用动态sql是因为技能超过100个。为所有100个技能ID显式添加数据是行不通的。谢谢……这看起来很有希望,查询与我尝试实现的类似。现在,我将运行实际表的查询,并查看得到的结果。我得到一个错误:列名“EmployeeID”无效。我认为这是表描述中的一个输入错误。将查询中的ed.EmployeeId
更改为ed.[Employee ID]
。这样做了。工作得很有魅力。你是救命恩人。谢谢你,我的荣幸!:)谢谢…这看起来很有希望,查询结果与我试图实现的结果类似。现在,我将运行实际表的查询,并查看得到的结果。我得到一个错误:列名“EmployeeID”无效。我认为这是表描述中的一个输入错误。将查询中的ed.EmployeeId
更改为ed.[Employee ID]
。这样做了。工作得很有魅力。你是救命恩人。谢谢你,我的荣幸!:)