SQL将多个记录透视到列
PIVOT和其他高级SQL对我来说非常陌生。我对SQL的经验仅限于基本查询和联接。我一直在努力使用这些工具,并安排了培训来提高我的SQL教育水平 同时,我希望从SO社区得到一些指导 我有一个表,其中包含数以万计的记录,我需要为这些记录生成一个特殊报告。对于一个人,该表可以有许多记录,但每个记录显然都是具有唯一信息的唯一记录 报告生成工具将请求特定时间段内特定人员的数据。这通常会列出1-7条记录。我相信我需要将每个记录显示为每个人的列 我附上了一张图片,试图说明起点和期望的输出。我和我的同事花了很多时间尝试这样做,他使用了PIVOT,但不是几年后,因为他最近不需要它 如果PIVOT不是正确的解决方案,我理解,但如果不是,我想排除它。我想我可以很容易地通过编程来完成我想要的事情,但是在DB服务器上而不是在应用程序中完成这项工作将大大减少报告生成时间SQL将多个记录透视到列,sql,sql-server,database,pivot,Sql,Sql Server,Database,Pivot,PIVOT和其他高级SQL对我来说非常陌生。我对SQL的经验仅限于基本查询和联接。我一直在努力使用这些工具,并安排了培训来提高我的SQL教育水平 同时,我希望从SO社区得到一些指导 我有一个表,其中包含数以万计的记录,我需要为这些记录生成一个特殊报告。对于一个人,该表可以有许多记录,但每个记录显然都是具有唯一信息的唯一记录 报告生成工具将请求特定时间段内特定人员的数据。这通常会列出1-7条记录。我相信我需要将每个记录显示为每个人的列 我附上了一张图片,试图说明起点和期望的输出。我和我的同事花了很
我希望在这里能找到一些清晰/帮助,因为我完全被难住了。对于这种输出,您应该使用动态sql的
PIVOT
。本文中有一个PIVOT-UNPIVOT和使用动态sql和PIVOT的好例子。有关PIVOT和UNPIVOT的更多信息,请参阅本文。对于这种输出,您应该将PIVOT与动态sql一起使用。本文中有一个PIVOT-UNPIVOT和使用动态sql和PIVOT的好例子。您可以在本文中查找有关PIVOT和UNPIVOT的更多信息,您必须使用动态SQL来获得所需的结果,因为在执行时,数据集应基于的可能值是未知的。您还需要以多列为轴心,这意味着您必须使用带有GROUP BY
子句的CASE
语句,或者将两列合并为一个轴心值列。使此查询更加复杂的是,[Type]
似乎会影响结果的显示方式
我在下面创建了一个示例,说明如何实现预期结果。我做了以下假设:
- 类型字段的值定义如下:1=观察值,2= 中期,3=总结性,6=总体
- 根据您的样本输出,在数据透视结果中,预期仅出现一次临时性、总结性和整体性观察
- 根据您的样本输出,观察者不会显示临时、总结和总体观察结果
-- Create some sample data
DECLARE @Observations TABLE
(
[Name] NVARCHAR(50) NOT NULL
,[Building] NVARCHAR(50) NOT NULL
,[Observation] DATETIME
,[Observer] NVARCHAR(50) NOT NULL
,[Type] INT
);
INSERT INTO @Observations
SELECT 'Doe, John', 'HQ', '01/01/2017', 'Doe, Jack', 1 UNION ALL
SELECT 'Doe, John', 'HQ', '02/01/2017', 'Doe, Jack', 1 UNION ALL
SELECT 'Doe, John', 'HQ', '03/01/2017', 'Doe, Jack', 2 UNION ALL
SELECT 'Doe, John', 'HQ', '04/01/2017', 'Doe, Jack', 1 UNION ALL
SELECT 'Doe, John', 'HQ', '05/01/2017', 'Doe, Jack', 1 UNION ALL
SELECT 'Doe, John', 'HQ', '06/01/2017', 'Doe, Jack', 3 UNION ALL
SELECT 'Doe, John', 'HQ', '07/01/2017', 'Doe, Jack', 6;
DECLARE @columns NVARCHAR(MAX) = N'';
DECLARE @selectClause NVARCHAR(MAX) = N'';
DECLARE @sql NVARCHAR(MAX);
CREATE TABLE #IntermResults
(
[Name] NVARCHAR(50) NOT NULL
,[Building] NVARCHAR(50) NOT NULL
,[PivotValue] NVARCHAR(50) NOT NULL
,[PivotID] NVARCHAR(50) NOT NULL
,[Observation] DATETIME NOT NULL
,[OrderRank] INT NOT NULL
)
-- Prepare the source data to make pivoting into desired format easier and store results into an interim temporary table.
;WITH ObservationsCTE
AS
(
SELECT [Name]
,[Building]
,[Observation]
,[Observer]
,[Type]
,(
CASE [Type]
WHEN 1 THEN 'Observation'
WHEN 2 THEN 'Interim'
WHEN 3 THEN 'Summative'
WHEN 6 THEN 'Overall'
ELSE 'UNKNOW'
END
) AS [ObservationType] -- Give descriptive values to Type column’s values. This will be used to help generate pivot table column names.
FROM @Observations
), ObservationsWithPivotIDs
AS
(
SELECT TOP 1000
[Name]
,[Building]
,CAST([Observation] AS NVARCHAR(50)) AS [PivotValue] -- Pivot value effectively combines the Observation & Observer column to help simplify the pivot query.
,'Observation' + CAST(ROW_NUMBER() OVER (PARTITION BY [Name] ORDER BY [Observation]) AS NVARCHAR(10)) AS [PivotID] -- Create a pivot id that will be used to generate pivoted columns.
,[Observation]
,1 AS [OrderRank] -- use this field to help order records.
FROM ObservationsCTE
WHERE [Type] = 1
UNION ALL
SELECT TOP 1000
[Name]
,[Building]
,[Observer] AS [PivotValue] -- Pivot value effectively combines the Observation & Observer column to help simplify the pivot query.
,'Observer' + CAST(ROW_NUMBER() OVER (PARTITION BY [Name] ORDER BY [Observation]) AS NVARCHAR(10)) AS [PivotID] -- Create a pivot id that will be used to generate pivoted columns.
,[Observation]
,2 AS [OrderRank] -- use this field to help order records.
FROM ObservationsCTE
WHERE [Type] = 1
UNION ALL
SELECT TOP 1000
[Name]
,[Building]
,CAST([Observation] AS NVARCHAR(50)) AS [PivotValue] -- Pivot value effectively combines the Observation & Observer column to help simplify the pivot query.
,[ObservationType] AS [PivotID]
,[Observation]
,1 AS [OrderRank] -- use this field to help order records.
FROM ObservationsCTE
WHERE [Type] <> 1
)
INSERT INTO #IntermResults -- Insert the results into an intermediate table.
(
[Name]
,[Building]
,[PivotValue]
,[PivotID]
,[Observation]
,[OrderRank]
)
SELECT [Name]
,[Building]
,[PivotValue]
,[PivotID]
,[Observation]
,[OrderRank]
FROM ObservationsWithPivotIDs
-- Determine what columns will be created for the pivot
SELECT @columns += N', ' + QUOTENAME([PivotID])
,@selectClause += N', ' + (CASE [OrderRank]
WHEN 1 THEN 'CAST(' + QUOTENAME([PivotID]) + ' AS DATETIME) AS ' + QUOTENAME([PivotID])
ELSE [PivotID]
END)
FROM #IntermResults
ORDER BY [Observation], [OrderRank]
-- Create dynamic query to create the pivot
SET @sql = N'
SELECT [Name], [Building], ' + STUFF(@selectClause, 1, 2, '') + '
FROM (
SELECT [Name]
,[Building]
,[PivotValue]
,[PivotID]
FROM #IntermResults
) i
PIVOT
(
MAX([PivotValue]) FOR [PivotID] IN ('
+ STUFF(@columns, 1, 1, '')
+ ')
) AS p;';
PRINT @sql;
-- Execute dynamic pivot query
EXEC sp_executesql @sql;
-- Drop intermediate results
DROP TABLE #IntermResults
——创建一些示例数据
声明@Observations表
(
[名称]NVARCHAR(50)不为空
,[Building]NVARCHAR(50)不为空
,[观察]日期时间
,[Observer]NVARCHAR(50)不为空
,[Type]INT
);
插入@Observations
选择“美国能源部,约翰”,“总部”,“2017年1月1日”,“美国能源部,杰克”,1个工会会员
选择“美国能源部,约翰”,“总部”,“2017年1月2日”,“美国能源部,杰克”,1个工会会员
选择“Doe,John”,“HQ”,“03/01/2017”,“Doe,Jack”,2个联合所有
选择“Doe,John”,“HQ”,“04/01/2017”,“Doe,Jack”,1个联合所有
选择“Doe,John”,“HQ”,“05/01/2017”,“Doe,Jack”,1个联合所有
选择“Doe,John”,“HQ”,“06/01/2017”,“Doe,Jack”,3个联合所有
选择'Doe,John','HQ','07/01/2017','Doe,Jack',6;
声明@columns NVARCHAR(MAX)=N'';
声明@selectClause NVARCHAR(MAX)=N';
声明@sql NVARCHAR(最大值);
创建表格#结果
(
[名称]NVARCHAR(50)不为空
,[Building]NVARCHAR(50)不为空
,[PivotValue]NVARCHAR(50)不为空
,[PivotID]NVARCHAR(50)不为空
,[Observation]日期时间不为空
,[OrderRank]INT不为空
)
--准备源数据,使数据透视转换为所需格式更容易,并将结果存储到临时表中。
;通过观察CTE
作为
(
选择[名称]
,[大厦]
,[观察]
,[观察员]
,[类型]
,(
案例[类型]
当我说“观察”
当2时,则为“临时”
当3时,则为“终结性”
当6时,则为“总体”
还有“未知”
结束
)AS[ObservationType]--为类型列的值提供描述性值。这将用于帮助生成透视表列名。
从@观察
),使用PivotId进行观测
作为
(
选择前1000名
[姓名]
,[大厦]
,将([Observation]转换为NVARCHAR(50))转换为[PivotValue]——PivotValue有效地结合了Observation和observator列,以帮助简化Pivot查询。
,'Observation'+CAST(ROW_NUMBER())(按[Name]划分,按[Observation]排序)作为NVARCHAR(10))作为[PivotID]--创建一个用于生成数据透视列的数据透视id。
,[观察]
,1为[OrderRank]--使用此字段帮助订购记录。
根据观测CTE
其中[Type]=1
联合所有
选择前1000名
[姓名]
,[大厦]
,[Observer]作为[PivotValue]——Pivot value有效地结合了“观察者”和“观察者”列,以帮助简化Pivot查询。
,'Observer'+将(按[Name]划分,按[Observation]排序)上的行数()转换为NVARCHAR(10))转换为[PivotID]--创建一个用于生成数据透视列的数据透视id。
,[观察]
,2作为[OrderRank]--使用