2013-07-30 54 views
-1

對於這樣一個表:PIVOT整列設置由

COL1 COL2 COL3 COL4 
item1 7/29/13 cat  blue 
item3 7/29/13 fish purple 
item1 7/30/13 rat  green 
item2 7/30/13 bat  grey 
item3 7/30/13 bird orange 

你會如何PIVOT度日COL2行,由COL1值將跨越重複阻止所有其他列?

COL2 COL1 COL3 COL4 COL1 COL3 COL4 COL1 COL3 COL4 
7/29/13 item1 cat  blue item2 NULL NULL item3 fish purple 
7/30/13 item1 rat  green item2 bat  grey item3 bird orange 
+0

(或更好的迭代連接本身)? – user2044384

+0

最後評論:項目數量可能會發生變化(可能會增加幾個 - 但不是> 10) - 因此,表格與其自身在每個項目值上的靜態連接並不理想。謝謝! – user2044384

+0

考慮處理應用程序級代碼/表示層中的數據顯示問題(如果有)(例如,將有序結果集傳遞給PHP循環)。它更加靈活。 – Strawberry

回答

2

爲了得到這樣的結果,你需要做幾件事情:

  1. 獲取值從col1和鮮明的列表col2
  2. unpivot的數據列中的col1col3col4
  3. 從未轉移的結果中樞轉的結果

要獲得日期,並從現有的表中的值以及物品(col1和COL2)的不同的列表中,您將需要使用類似以下內容:

select t.col1, t.col2, 
    t2.col3, t2.col4, 
    row_number() over(partition by t.col2 
         order by t.col1) seq 
from 
(
    select distinct t.col1, c.col2 
    from yourtable t 
    cross join 
    (
    select distinct col2 
    from yourtable 
) c 
) t 
left join yourtable t2 
    on t.col1 = t2.col1 
    and t.col2 = t2.col2; 

SQL Fiddle with Demo。一旦你有這個列表,那麼你將需要取消數據。有幾種方法可以做到這一點,使用UNPIVOT功能或使用交叉適用於:

select d.col2, 
    col = col+'_'+cast(seq as varchar(10)), 
    value 
from 
(
    select t.col1, t.col2, 
    t2.col3, t2.col4, 
    row_number() over(partition by t.col2 
         order by t.col1) seq 
    from 
    (
    select distinct t.col1, c.col2 
    from yourtable t 
    cross join 
    (
     select distinct col2 
     from yourtable 
    ) c 
) t 
    left join yourtable t2 
    on t.col1 = t2.col1 
    and t.col2 = t2.col2 
) d 
cross apply 
(
    select 'col1', col1 union all 
    select 'col3', col3 union all 
    select 'col4', col4 
) c (col, value); 

SQL Fiddle with Demo。這會給你看起來像數據:

|      COL2 | COL | VALUE | 
------------------------------------------------- 
| July, 29 2013 00:00:00+0000 | col1_1 | item1 | 
| July, 29 2013 00:00:00+0000 | col3_1 | cat | 
| July, 29 2013 00:00:00+0000 | col4_1 | blue | 
| July, 29 2013 00:00:00+0000 | col1_2 | item2 | 
| July, 29 2013 00:00:00+0000 | col3_2 | (null) | 
| July, 29 2013 00:00:00+0000 | col4_2 | (null) | 

最後,你將適用於旋轉功能在col列的項目:

select col2, 
    col1_1, col3_1, col4_1, 
    col1_2, col3_2, col4_2, 
    col1_3, col3_3, col4_3 
from 
(
    select d.col2, 
    col = col+'_'+cast(seq as varchar(10)), 
    value 
    from 
    (
    select t.col1, t.col2, 
     t2.col3, t2.col4, 
     row_number() over(partition by t.col2 
          order by t.col1) seq 
    from 
    (
     select distinct t.col1, c.col2 
     from yourtable t 
     cross join 
     (
     select distinct col2 
     from yourtable 
    ) c 
    ) t 
    left join yourtable t2 
     on t.col1 = t2.col1 
     and t.col2 = t2.col2 
) d 
    cross apply 
    (
    select 'col1', col1 union all 
    select 'col3', col3 union all 
    select 'col4', col4 
) c (col, value) 
) src 
pivot 
(
    max(value) 
    for col in (col1_1, col3_1, col4_1, 
       col1_2, col3_2, col4_2, 
       col1_3, col3_3, col4_3) 
)piv; 

SQL Fiddle with Demo。如果你有一個未知的數值,那麼你可以使用動態SQL來得到結果:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(seq as varchar(10))) 
        from 
        (
         select row_number() over(partition by col2 
                order by col1) seq 
         from yourtable 
        ) t 
        cross apply 
        (
         select 'col1', 1 union all 
         select 'col3', 2 union all 
         select 'col4', 3 
        ) c (col, so) 
        group by col, seq, so 
        order by seq, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT col2, ' + @cols + ' 
      from 
      (
       select d.col2, 
        col = col+''_''+cast(seq as varchar(10)), 
        value 
       from 
       (
        select t.col1, t.col2, 
        t2.col3, t2.col4, 
        row_number() over(partition by t.col2 
             order by t.col1) seq 
        from 
        (
        select distinct t.col1, c.col2 
        from yourtable t 
        cross join 
        (
         select distinct col2 
         from yourtable 
        ) c 
       ) t 
        left join yourtable t2 
        on t.col1 = t2.col1 
        and t.col2 = t2.col2 
       ) d 
       cross apply 
       (
        select ''col1'', col1 union all 
        select ''col3'', col3 union all 
        select ''col4'', col4 
       ) c (col, value) 
      ) x 
      pivot 
      (
       max(value) 
       for col in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

SQL Fiddle with Demo。所有版本會給結果:

|      COL2 | COL1_1 | COL3_1 | COL4_1 | COL1_2 | COL3_2 | COL4_2 | COL1_3 | COL3_3 | COL4_3 | 
---------------------------------------------------------------------------------------------------------------- 
| July, 29 2013 00:00:00+0000 | item1 | cat | blue | item2 | (null) | (null) | item3 | fish | purple | 
| July, 30 2013 00:00:00+0000 | item1 | rat | green | item2 | bat | grey | item3 | bird | orange | 
0

動態UNPIVOT + PIVOT方法總是冷靜,做這樣的事情,當一個已知的和有限的一組數值的連續JOIN的工作很好太(正對懶惰SELECT列表):

WITH cte AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY COL2 ORDER BY COL1)'RowRank' 
      FROM #Table1) 
SELECT * 
FROM cte a 
LEFT JOIN cte b 
    ON a.COL2 = b.COL2 
    AND a.RowRank = b.RowRank - 1 
LEFT JOIN cte c 
    ON b.COL2 = c.COL2 
    AND b.RowRank = c.RowRank - 1 
WHERE a.RowRank = 1 

或者,如果字段的順序是要保持:

WITH cte AS (SELECT a.*,b.RowRank 
      FROM #Table1 a 
      JOIN (SELECT Col1,ROW_NUMBER() OVER (ORDER BY Col1)'RowRank' 
        FROM #Table1 
        GROUP BY COL1) b 
       ON a.Col1 = b.Col1) 
SELECT * 
FROM cte a 
LEFT JOIN cte b 
    ON a.COL2 = b.COL2 
    AND a.RowRank = b.RowRank - 1 
LEFT JOIN cte c 
ON a.COL2 = c.COL2 
    AND a.RowRank = c.RowRank - 2 
WHERE a.RowRank = 1 

但是,如果沒有'錨'的價值,這將崩潰,即如果沒有記錄item1在給定的日期它不會被包括在內。

+0

關於保持值的順序相同(http://sqlfiddle.com/#!3/471ab/25)意味着item1列,然後item2列等的建議? – Taryn

+0

啊,是的,如果訂單很重要,可能會有問題,可以使用Col1值的不同列表,但如果沒有錨值,後續的JOIN方法將崩潰。 –