所以我有这个动态查询返回一个具有动态列数的结果集,如下所示:
在这个结果集中,我们有ID,FacilityName和cycleNum的列将始终存在,但任务列的数量可以变化Task1,Task2,Task3 ..... upto Taskn。
我需要的最终结果集如下:
为此我尝试了这个查询:
Select distinct FacilityName,
substring(
(
Select ',' + a
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar) + ';' as a FROM #tempTable) ST1
Where ST1.FacilityName = ST2.FacilityName
ORDER BY ST1.FacilityName
For XML PATH ('')
), 2, 1000) CycleData
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar)+ ';' as a FROM #tempTable) ST2
这将适用于以下测试数据:
create table #tempTable
(
ID int,
FacilityName varchar(50),
CycleNum int,
Task1 datetime,
Task2 datetime,
Task3 datetime
)
Insert into #tempTable values
(1, 'A', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(2, 'A', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(3, 'B', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(4, 'B', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126))
但我想不出任何方法来扩展它以使用动态列。所有列的列表都保存在主表中,因此如果需要,我们可以从那里获得以逗号分隔的列列表。
答案 0 :(得分:1)
这是一种动态的方式
与静态查询略有不同的方法。要使其动态化,请使用while
循环或CURSOR
生成Task1 + Task2 + ..TaskN
。然后在Select
查询中使用它。
DECLARE @columns VARCHAR(50)='Task1,Task2,Task3', -- Pass the list of column names
@int INT = 1,
@sql VARCHAR(8000)
SET @sql = ' ;WITH cte
AS (SELECT *,
''Cycle-'' + Cast(CycleNum AS VARCHAR(10)) + ''::'' '
WHILE @int <= Len(@columns) - Len(Replace(@columns, ',', '')) -- To find the number of Tasks in list
BEGIN
SET @sql += + '+''Task' + Cast(@int AS VARCHAR(10))
+ '~''+' + 'Cast(Task'
+ Cast(@int AS VARCHAR(10))
+ ' AS VARCHAR(50)) + '','''
SET @int += 1
END
SET @sql += ' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + '',''
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('''')) cs (CycleData)
'
--print @sql -- uncomment it to debug if you have any error when executing dynamic code
EXEC (@sql)
不要担心While Loop/CURSOR
的使用,因为我们没有在循环中进行任何资源密集型操作。
静态查询将如下所示
;WITH cte
AS (SELECT *,
'Cycle-' + Cast(CycleNum AS VARCHAR(10))
+ '::' + 'Task1~' + Cast(Task1 AS VARCHAR(50))
+ ',' + 'Task2~' + Cast(Task2 AS VARCHAR(50))
+ ',' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + ','
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('')) cs (CycleData)
答案 1 :(得分:1)
使用系统表。我更喜欢简短有效的解决方案:)。这是指南,我相信你可以通过集中字符串自己完成它(如果你不确定,添加评论,我将添加整个代码或更多描述)。
declare @columns varchar(max)
SELECT @columns = isnull(@columns + '+', '') + '''' + COLUMN_NAME + '~'' + Cast(' + COLUMN_NAME + ' as varchar(50))'
FROM tempdb.INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME like '#tempTable%'
AND c.COLUMN_NAME LIKE 'Task%' -- filter columns you are interested in
declare @sql varchar(4000) = 'select *, ' + @columns + ' from #tempTable'
print @sql
exec (@sql)