SQL/TSQL:在多个表上使用 PIVOT

Posted

技术标签:

【中文标题】SQL/TSQL:在多个表上使用 PIVOT【英文标题】:SQL/TSQL: Using PIVOT on multiple tables 【发布时间】:2014-11-25 20:36:15 【问题描述】:

我正在尝试用 SQL 中的 PIVOT 解决两个类似的问题。我有三张桌子:

第一个包含列:orderid、empid、orderdate; 第二列:orderid、productid、unitprice 第三个包含列:empid、firstname、lastname 等(有关工作人员的其他信息)

现在,我需要使用 PIVOT 来管理这样的事情:

empid firstname lastname 2006 2007 2008
1     aaa       bbb      1    55    77
1     aaa       bbb      2    58    79
2     xxx       ccc      4    59    82
....................................... 

其中 2006、2007、2008 列中的数字是为每年分配的 orderid。

我有这样的事情(Pivott 内部的查询工作正常):

WITH Pivott AS
(
    SELECT
        so.empid, 
        YEAR(so.orderdate),
        so.orderid,
        hr.lastname,
        hr.firstname
    FROM 
        Sales.Orders so
    LEFT OUTER JOIN
        HR.Employees hr ON so.empid = hr.empid
)
SELECT 
    YEAR(orderdate), [2006], [2007], [2008]
FROM 
    Pivott
PIVOT
    (SUM(orderid) FOR YEAR(orderdate) IN [2006], [2007], [2008]) AS PIV;

还有第二个问题:

我也尝试使用 PIVOT 来管理这样的事情:

empid firstname lastname 2006  2007  2008
1     aaa       bbb      453   34    77
2     vvv       kkk      345   89    123
3     xxx       ccc      453   12    82
....................................... 

其中 2006、2007、2008 列中的数字是工人 (empid) 在给定年份执行的订单的所有价格的总和。

我有这个:

WITH Pivott AS
(
    SELECT
        so.empid,
        YEAR(so.orderdate) AS YEAR,
        so.orderid AS ORDERS,
        hr.lastname,
        hr.firstname,
        s.unitprice AS SUMA
    FROM 
        Sales.Orders so
    LEFT OUTER JOIN
        HR.Employees hr ON so.empid = hr.empid
    INNER JOIN
        Sales.OrderDetails s ON so.orderid = s.orderid
)
SELECT 
    YEAR(orderdate), [2006], [2007], [2008]
FROM 
    Pivott
PIVOT
    (SUM(unitprice) FOR YEAR(orderdate) IN ([2006], [2007], [2008])) AS PIV;

我需要改变什么来实现我想要的输出?

感谢您的宝贵时间!

【问题讨论】:

您的查询有什么问题?为什么你的初始结果有多次emp id? @radar 感谢您的回复!我有语法问题,例如现在我有错误“Msg 102, Level 15, State 1, Line 16 Incorrect syntax near '('."。所以我在 Pivott 内部做错了,但独立地这个查询工作正常。在我的第一个初始结果中,我想显示给定年份和工人的所有订单数 (orderid)(例如,有人在 2006 年执行了四个订单,所以它应该每年显示他们的 orderid)。 你能从两个表中给出几行来尝试查询 你能把每个数据的示例数据连同表结构一起发布吗?最好创建一个sqlfiddle.com @radar:我会将它们粘贴到上面的问题中。 【参考方案1】:

您似乎正在尝试对 CTE 应用 Pivot 命令

试试这个;

;WITH pvtCTE AS
(SELECT so.empid,
YEAR(so.orderdate) AS SalesYEAR,
--so.orderid AS ORDERS, /** removed from grouping**/
hr.lastname,
hr.firstname,
SUM(ISNULL(s.unitprice,0.00)) as unitprice /** pre grouping adjusted per comment**/
FROM Sales.Orders so
left outer join HR.Employees hr on so.empid = hr.empid
inner join Sales.OrderDetails s on so.orderid = s.orderid
GROUP BY so.empid, YEAR(so,orderDate), hr.lastname, hr.firstname --added for aggregated CTE results
)

SELECT empid, firstname, lastname, [2006], [2007], [2008]
FROM (SELECT * FROM pvtCTE) p
PIVOT (
SUM(unitprice)
FOR SalesYEAR IN ([2006],[2007],[2008])
) as pvt;

【讨论】:

非常感谢您纠正我无效的代码。但是,结果只有一半令人满意,我在某处犯了错误。我的输出现在看起来像这样:每个 orderid 有几次 empid,每个 orderid 的所有单价都有一个总和,首先是 2006 年,接下来是 2007 年和 2008 年的 NULL,然后另一行是另一行订单号。您是否知道每个 empid 的所有单价和所有订单按年接收总和的变化?再次非常感谢您的回复! 好吧,如果您不关心实际的 OrderID,您可以将其从 select 语句中一起删除。您是说您只想根据员工和年份对其进行分组? 哇。这么简单的答案,让我很困惑!这是我需要的。非常感谢,现在我知道如何处理了。 (不知道谁给了你答案“-1”,我给你“+1”)。 您不需要额外的(select * from pvtCTE) 来获得结果。 从技术上讲,您根本不需要 CTE,您可以将原始选择嵌套在括号中。重点是划定这两个组成部分。

以上是关于SQL/TSQL:在多个表上使用 PIVOT的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中使用“Pivot”将行转换为列

SQL Server - Pivot 将行转换为列(带有额外的行数据)

SQLServer 2008 PIVOT 上的多个字段问题

如何在不使用临时表或视图的情况下在多个列上使用 PIVOT [重复]

使用 PIVOT 格式化多个 SELECT 语句

使用函数 pivot_longer() 时如何排除多个列? [复制]