2016-12-30 9 views
1

だから持っているので、同様にカラムの動的数を有する結果セットを返し、このダイナミッククエリ:を連結列

enter image description here

をこの結果セットには、ID、FacilityNameの列があり、cycleNumは常にそこにありますが、タスク列の数はTask1、Task2、Task3 ..... tasksnまで変化する可能性があります。

次のように私は必要な最終的な結果セットは次のとおりです。

このため

enter image description here

私はこのクエリを試してみました:

 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)) 

しかし、これを拡張して動的なcを使う方法はないと思いますolumns。すべての列のリストはマスター表に保存されているため、必要に応じてカンマ区切りの列リストをそこから取得できます。

答えて

0

ここは動的な方法です

静的クエリとは少し異なるアプローチです。動的にするには、whileループまたはCURSORを使用してTask1 + Task2 + ..TaskNを生成します。その後、Selectクエリで使用します。私たちは、ループ内の任意のリソース集中型の操作を行っていないので、While Loop/CURSORの使用を心配する未

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) 

静的クエリは、この

;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) 
0

利用システムテーブルのように見えるだろう。私は短くて効果的なソリューションを好む:)。これはガイドです。文字列を集中して自分で終えることができると確信しています(わからない場合はコメントを追加し、コード全体または詳細を追加します)。

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)