在 SQL 中使用“Pivot”将行转换为列
Posted
技术标签:
【中文标题】在 SQL 中使用“Pivot”将行转换为列【英文标题】:Convert Rows to columns using 'Pivot' in SQL 【发布时间】:2020-12-01 23:26:06 【问题描述】:我已经阅读了 MS 数据透视表上的内容,但我仍然无法正确解决这个问题。
我对这些结果有看法
Invoice Date Basecard Item Quantity Subtotal Taxes Total
713938 09/11/2020 C90001 Desktop 14 2800 448 3248
713938 09/11/2020 C90001 Laptop 18.5 29091.25 4654.6 33745.85
我希望它以数据透视表的形式出现,如下所示:
Invoice Date Basecard Laptop Desktop Subtotal Taxes Total
713938 09/11/2020 C90001 18.5 14 31891.25 5102.6 36993.85
这是我的查询
SELECT * FROM (
SELECT Invoice, Date, BaseCard, Item, sum(Quantity) Qty, sum(Subtotal) Subtotal
FROM MyView
Group by Invoice, Date, BaseCard, Item, Subtotal
) Resultados
PIVOT (
Sum(Qty)
FOR Item
IN (
[Laptop], [Desktop]
)
) AS PivorTable
Group by Invoice, Date, BaseCard, Laptop, Desktop, Subtotal
结果
Invoice Date baseCard subtotal Laptop Desktop
713938 2020-11-09 C90001 2800.00 NULL 14.000000
713938 2020-11-09 C90001 7076.25 4.50 NULL
713938 2020-11-09 C90001 22015.000 14.00 NULL
【问题讨论】:
【参考方案1】:假设你有这样一张桌子
CREATE TABLE [InvoiceInfo](
[Invoice] INT,
[Date] DATE,
[Basecard] VARCHAR(100),
[Item] VARCHAR(100),
[Quantity] FLOAT,
[Price] FLOAT
)
您从中创建视图。考虑到这一点,我可以建议您使用条件聚合来简化您的数据透视,并根据当前存在的[Item]
值转换为动态格式以使其灵活,例如
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX)
SET @cols = ( SELECT STRING_AGG(
CONCAT('SUM(CASE WHEN [Item]=''',[Item],
''' THEN [Quantity] END) AS [',[Item],']'),',')
FROM (SELECT DISTINCT [Item]
FROM [InvoiceInfo] ) i );
SET @query = CONCAT(
N'SELECT [Invoice], [Date], [BaseCard],', @cols ,
N' ,SUM([Price]*[Quantity]) AS [Subtotal],
SUM(ROUND([Price]*[Quantity]*.16, 2)) AS [Taxes],
SUM([Price]*[Quantity])+SUM(ROUND([Price]*[Quantity]*.16, 2)) AS [Total]
FROM [InvoiceInfo] i
GROUP BY [Invoice], [Date], [BaseCard]');
EXEC sp_executesql @query;
Invoice Date BaseCard Desktop Laptop Subtotal Taxes Total
713938 2020-11-09 C90001 14 18.5 31891.25 5102.6 36993.85
更新:根据您最近声明的旧数据库版本,您可以使用以下代码,包括 FOR XML PATH
和 STUFF
来替代 STRING_AGG
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
SELECT @cols =
STUFF((SELECT DISTINCT ',' +
CONCAT('SUM(CASE WHEN [Item]=''',[Item],
''' THEN [Quantity] END) AS [',[Item],']')
AS formulas
FROM
(
SELECT DISTINCT [Item]
FROM [InvoiceInfo] f
) ff
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @query = CONCAT(
N'SELECT [Invoice], [Date], [BaseCard],', @cols ,
N' ,SUM([Price]*[Quantity]) AS [Subtotal],
SUM(ROUND([Price]*[Quantity]*.16, 2)) AS [Taxes],
SUM([Price]*[Quantity])+SUM(ROUND([Price]*[Quantity]*.16, 2)) AS [Total]
FROM [InvoiceInfo] i
GROUP BY [Invoice], [Date], [BaseCard]');
EXEC sp_executesql @query;
Demo
【讨论】:
感谢您的帮助 Barbaros,但我有 SQL Server 2015 并且在运行查询时出现此错误。 -- STRING_AGG 不是可识别的内置函数名称 -- CONCAT 不是可识别的内置函数名称 嗨@Andros,不客气。由于您的数据库版本,我已更新。 对不起 Babaros,我的错误,我的 SQL 版本是 2005。我试图让它工作,但我做不到。你帮了大忙【参考方案2】:您也只需要总结这些关键数据。您的行已拆分,因为您已将 subtotal
列添加到分组依据。
db<>fiddle
with a as (
select 713938 as invoice, convert(date, '2020-11-09', 23) as dt, 'C90001' as Basecard, 'Desktop' as item, 14 as quantity, 2800 as subtotal, 448 as taxes, 3248 as total
union all
select 713938, convert(date, '2020-11-09', 23), 'C90001', 'Laptop', 18.5, 29091.25, 4654.6, 33745.85
)
select
invoice,
dt,
basecard,
sum([Desktop]) as desctop,
sum([Laptop]) as laptop,
sum(subtotal) as subtotal,
sum(taxes) as taxes,
sum(total) as total
from a
pivot (
sum(quantity) for item in ([Desktop], [Laptop])
) as q
group by
invoice,
dt,
basecard
invoice | dt | basecard | desctop | laptop | subtotal | taxes | total
------: | :--------- | :------- | ------: | -----: | -------: | -----: | -------:
713938 | 2020-11-09 | C90001 | 14.0 | 18.5 | 31891.25 | 5102.6 | 36993.85
【讨论】:
感谢您的帮助,这几乎可以完美运行,如何转换为动态格式以使其灵活?因为我有更多的项目 @Andros 没有办法在静态 SQL 中使其动态化(我认为因为解析器在执行之前应该知道确切的列名)。因此,唯一的方法是使用动态 SQL,正如另一个答案中所述。还有很多例子:one、two 和,糟糕但有效,从第二个得到,three。以上是关于在 SQL 中使用“Pivot”将行转换为列的主要内容,如果未能解决你的问题,请参考以下文章