在 SQL Server 表中加入和分组后转置行

Posted

技术标签:

【中文标题】在 SQL Server 表中加入和分组后转置行【英文标题】:Transpose rows after Join and Groupby in SQL Server table 【发布时间】:2020-09-12 05:32:54 【问题描述】:

我有一些 SQL Server 表:

员工 [EmpID (pk)、姓名、职务] 项目 [PID (pk)、EmpID (fk)、PCode、PName、Dept]

这些表是多对一的关系,也就是说,一个员工可以处理多个项目。

我想以这样一种方式显示结果,即每个员工只有一行,并且他从事的所有项目都显示在根据 PCode 分组的列部分中。

当生成的列数未知时,我无法理解如何将行转置到列中。

样本数据:

员工:

EmpId  Name  Designation
------------------------
001    Mat   Manager
002    Ash   Developer
003    Paul  Analyst

项目:

PID EmpID PCode PName       Dept
-------------------------------------
1   001   111   Project1    Sales
2   001   111   Project1.1  Retail
3   001   222   Project2    Banking
4   002   222   Project2.1  Retail   

样本输出:

EmpID Name Project-1           Project-2              Project-3           
---------------------------------------------------------------------------
001   Abc  111,Project1,Sales  111,Project1.1,Retail  222,Project2,Banking
002   Def  222,Project2.1,Retail

【问题讨论】:

以表格格式提供样本数据和您想要的输出 更新了问题。请检查 你使用的是哪个版本的sql server 请向我们展示您的尝试。 【参考方案1】:

您可以使用row_number() 在子查询中枚举每个员工的项目,然后使用条件聚合在外部查询中进行透视:

select e.empid, e.name,
    max(case when rn = 1 then concat_ws(',', p.pcode, p.pname, p.pdept) end) project1,
    max(case when rn = 2 then concat_ws(',', p.pcode, p.pname, p.pdept) end) project2,
    max(case when rn = 3 then concat_ws(',', p.pcode, p.pname, p.pdept) end) project3
from employee e
inner join (
    select p.*, row_number() over(partition by empid order by pid) rn
    from projects p
) p on p.empid = e.empid
group by e.empid, e.name

【讨论】:

它给了我这个错误“错误代码:1064 您的 SQL 语法有错误;请查看与您的 mysql 服务器版本相对应的手册,以在 '(按 empid 顺序分区)附近使用正确的语法通过 pid) rn @user8306074:这是一条 MySQL 错误消息。你为什么要标记你的问题 SQL Server? row_number() 我只在 MySQL 8.0 中可用。 我有一个庞大的数据集,不知道每个员工的最大项目数。那么,在那种情况下,我如何生成多个项目列?【参考方案2】:

您可以使用PIVOT 命令转置您的数据。对于您未知的情况,生成的列数是未知的。您需要查询生成列的列名,然后您可以使用PIVOT 命令将所有列名连接起来,如下查询语句。

DECLARE @columnName NVARCHAR(MAX), @pivotSql NVARCHAR(MAX)
SELECT 
    em.EmpID,
    em.Name,
    pr.Pname,
    pr.Pcode + ',' + pr.PName + ',' + pr.Dept Detail
INTO #temp
FROM Employee em 
INNER JOIN Projects pr ON em.EmpID = pr.EmpID 

SELECT 
    t.PName name
INTO #AllProject
FROM #temp t
GROUP BY t.PName

SET @columnName = '';

DECLARE 
    @projectName VARCHAR(MAX);

DECLARE cursor_allProject CURSOR
FOR SELECT 
        name
    FROM 
        #AllProject;
OPEN cursor_allProject;
FETCH NEXT FROM cursor_allProject INTO @projectName;
WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @columnName = @columnName + ', [' + @projectName + ']';
        FETCH NEXT FROM cursor_allProject INTO @projectName;
    END;
CLOSE cursor_allProject;
DEALLOCATE cursor_allProject;


SET @pivotSql = 'SELECT t.EmpID, t.Name FROM #temp t PIVOT t.Detail (FOR t.Pname IN ('+ @columnName +') )'

EXEC (@pivotSql)

【讨论】:

您使用的是哪个版本的 SQL? 您可以与任何 SQL Server 一起使用

以上是关于在 SQL Server 表中加入和分组后转置行的主要内容,如果未能解决你的问题,请参考以下文章

如何在需要按一个键列分组的 3 个表中加入和求和值

在 Hadoop Pig 中加入和分组

PostgreSQL 交叉表转置行到列

对列名排序后转置和添加前缀的宏

MySQL如何按列转置行

仅使用最小 COUNT() 转置行和列(又名枢轴)?