【问题标题】:Join tables and Union All/ Pivot/ Unpivot?加入表和联合所有/透视/取消透视?
【发布时间】:2017-02-07 07:28:35
【问题描述】:

我在数据库中有四个表:

表 1:Employee_Details

-----------------------------------------------------------------------
| Employee ID | Name  | Department |DateofJoining |
-----------------------------------------------------------------------
|             |       |            |              |
| e1          | name1 | d1         | date1        |
| e2          | name2 | d2         | date2        |
| e3          | name3 | d3         | date3        |
-----------------------------------------------------------------------

表 2:Employee_SkillSet

----------------------------------------------------------------------------
| 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_Certifications

-----------------------------------------------------------------------
| EmployeeID | CertificationID |  Name  |
-----------------------------------------------------------------------
|            |                 |        |
| e1         | c1              | cname1 |
| e1         | c2              | cname2 |
| e2         | c3              | cname3 |
-----------------------------------------------------------------------

表 4:Other_Details

----------------------------------------------------------------------------
| 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')

创建脚本:

【问题讨论】:

  • 不就是对empID的加入吗?您可能需要的唯一东西是用于连接列(例如认证)的 STUFF FOR XML PATH('') 语句。
  • 是的,它是 EmpId 上的联接。我想不通的是如何旋转结果表,以便与一个 EmpID 对应的所有数据都在一行中

标签: sql sql-server sql-server-2008 tsql join


【解决方案1】:

你可以使用:

  • FOR XML PATH('') 获取逗号分隔值
  • 动态 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 来传递逗号分隔值。

【讨论】:

  • 谢谢...这看起来很有希望,并且查询类似于我试图实现的。我现在将对实际表运行查询,看看我得到了什么。
  • 我收到一个错误:列名“EmployeeID”无效。
  • 我认为这是您的表格描述中的拼写错误。在查询中将ed.EmployeeId 更改为ed.[Employee ID]
  • 做到了。像魅力一样工作。你是救命稻草。谢谢
  • 我的荣幸! :)
【解决方案2】:

您可以使用以下方法,而不是使用动态 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是因为skills超过100个。明确添加所有100个skill id的数据是不行的。
【解决方案3】:
Select TBl1.[EmployeeID],Tbl1.Name,Tbl1.Department,TBl1.Qualification, TBl1.TotalExp ,TBl1.Specialization,TBl1.[Certifications]
,Skill1_Exp,Skill1_Rating
,Skill2_Exp,Skill2_Rating
,Skill3_Exp,Skill3_Rating
From
(
    Select TBl1.[EmployeeID],Tbl1.Name,Tbl1.Department,Tbl4.Qualification, Tbl4.TotalExp ,Tbl4.Specialization,Tbl3.[Certifications]
    From Employee_Details Tbl1 Inner Join Employee_SkillSet Tbl2
    On TBl1.[EmployeeID]=TBl2.[EmployeeID]
    Inner Join 
    (
        SELECT Dtl.[EmployeeID],
                    STUFF((    SELECT ',' + Cer.CertificationID AS [text()]
                                FROM Employee_Certifications Cer
                                WHERE
                                Cer.[EmployeeID] = Dtl.[EmployeeID]
                                FOR XML PATH('')
                                ), 1, 1, '' )
                    AS [Certifications]
        FROM  Employee_Details Dtl
    ) as Tbl3
    On Tbl1.[EmployeeID]=Tbl3.[EmployeeID]
    Inner Join Other_Details as Tbl4
    On Tbl1.[EmployeeID]=Tbl4.[EmployeeID] 
    Group by TBl1.[EmployeeID],Tbl1.Name,Tbl1.Department,Tbl4.Qualification, Tbl4.TotalExp ,Tbl4.Specialization,Tbl3.[Certifications]
)as Tbl1
Inner Join
(
    Select Tbl1.[EmployeeID],Tbl1.skill1 as Skill1_Exp,Tbl2.skill1 as Skill1_Rating
    ,Tbl1.skill2 as Skill2_Exp,Tbl2.skill2 as Skill2_Rating
    ,Tbl1.skill3 as Skill3_Exp,Tbl2.skill3 as Skill3_Rating
    From
    (
        Select *
        from (seLECT [employeeID],SKILLNAME,SkillExperience FROM Employee_SkillSet )P
        PIVOT
        (max(SkillExperience )
            FOR SkillName IN([skill1], [skill2],[skill3])
        ) AS PivotSales 
    )as Tbl1
    Inner Join
    (
        Select *
        from (seLECT [employeeID],SKILLNAME,SKILLRATING FROM Employee_SkillSet )P
        PIVOT
        (
            max(SkillRating) 
            FOR SkillName IN([skill1], [skill2],[skill3])
        ) AS PivotSales
    )as Tbl2
    On Tbl1.[EmployeeID]=Tbl2.[EmployeeID]
) as Tbl2
On Tbl1.[EmployeeID]=Tbl2.[EmployeeID]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 2021-11-19
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    相关资源
    最近更新 更多