我有一个表,其中包含未知数量的任务,像这样:
+----------+--------+--------+--------+--------+--------+
| CourseID | Task 1 | Task 2 | Task 3 | Task 4 | Task 5 |
+----------+--------+--------+--------+--------+--------+
| EN01 | 15 | 20 | 15 | 25 | 30 |
+----------+--------+--------+--------+--------+--------+
有时有5个任务,有时还有更多任务。我如何使用数据透视表编写动态转置查询以获取此结果,而不必专门修饰除列标题之外的其他列标题,例如“ Task%”
+----------+-------------+------------+
| CourseID | Task Number | Task Total |
+----------+-------------+------------+
| EN01 | Task 1 | 15 |
| EN01 | Task 2 | 20 |
| EN01 | Task 3 | 15 |
| EN01 | Task 4 | 25 |
| EN01 | Task 5 | 30 |
+----------+-------------+------------+
编辑:基本上,我需要相反的操作:Efficiently convert rows to columns in sql server
我可以手动完成:
-- Unpivot the table.
SELECT [Class], TaskNumber, TaskTotal
FROM
(SELECT [Class], [Task 1], [Task 2], [Task 3], [Task 4]
FROM [Modules].[dbo].[2018-12ah] where [Given] like '%J:%') p
UNPIVOT
(TaskTotal FOR TaskNumber IN
([Task 1], [Task 2], [Task 3], [Task 4])
)AS Unpivot;
GO
下一步,我不确定该如何在任务1到Z中动态构建,因此不必在查询中指定它们。
谢谢
答案 0 :(得分:0)
您可以将INFORMATION_SCHEMA
中的信息用于动态TSQL,但要注意安全隐患(即SQL注入):
create table [dbo].[Test] ([CourseID] nvarchar(50), [Task 1] int, [Task 2] int, [Task 3] int, [Task 4] int, [Task 5] int)
insert into [dbo].[Test] select 'EN01', 15,20,15,25,30
declare @sql nvarchar(max) = ''
declare @cols nvarchar(max) = ''
select @cols = @cols +','+ QUOTENAME(COLUMN_NAME)
from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA='dbo' and TABLE_NAME='test' and COLUMN_NAME like 'Task%'
order by ORDINAL_POSITION
set @cols = substring(@cols, 2, LEN(@cols))
set @sql = @sql + ' select u.[CourseID], u.[TaskNumber], u.[TaskTotal] '
set @sql = @sql + ' from [dbo].[Test] s '
set @sql = @sql + ' unpivot '
set @sql = @sql + ' ( '
set @sql = @sql + ' [TaskTotal] '
set @sql = @sql + ' for [TaskNumber] in ('+ @cols + ') '
set @sql = @sql + ' ) u;'
execute(@sql)
包含5个任务的结果:
如果更改表结构,请添加新的任务列:
DROP TABLE [dbo].[Test]
create table [dbo].[Test] ([CourseID] nvarchar(50), [Task 1] int, [Task 2] int, [Task 3] int, [Task 4] int, [Task 5] int, [Task 6] int)
insert into [dbo].[Test] select 'EN01', 15,20,15,25,30,1000
同一查询将返回此结果集:
如果您更喜欢使用CROSS APPLY
方法来取消透视,这里是替代解决方案:
create table [dbo].[Test] ([CourseID] nvarchar(50), [Task 1] int, [Task 2] int, [Task 3] int, [Task 4] int, [Task 5] int)
insert into [dbo].[Test] select 'EN01', 15,20,15,25,30
declare @sql nvarchar(max) = ''
declare @values nvarchar(max) = ''
select @values = @values +',(''' + COLUMN_NAME + ''','+ QUOTENAME(COLUMN_NAME) + ')'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA='dbo' and TABLE_NAME='test' and COLUMN_NAME like 'Task%'
order by ORDINAL_POSITION
set @values = substring(@values, 2, LEN(@values))
set @sql = @sql + ' Select [CourseID], B.* '
set @sql = @sql + ' From [dbo].[Test] '
set @sql = @sql + ' Cross Apply (values '
set @sql = @sql + @values
set @sql = @sql + ' ) B(TaskNumber, TaskTotal) '
execute(@sql)