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 Server - Pivot 将行转换为列(带有额外的行数据)