2017-08-08 175 views
3

我有一個SQL Server表表名,如:如何將單個整數值列拆分爲n列?

col1 
1 
2 
3 
4 
5 
6 
7 
8 
9 
. 
. 
. 
N 

我要像下面

col-1 | col-2 | col-3 | col-4 |col-5 
------------------------------- 
1  | 2  | 3  | 4  |5 
6  | 7  | 8  | 9  |10 
11 | 12 | 13 | 14 |15 

如何從SQL服務器查詢此輸出得到輸出。

+0

您正在使用什麼版本的SQL Server?如果是2016年,則有STRING_SPLIT功能。 – Leonidas199x

+1

也許表樞軸將在這裏幫助? – Mat

+0

謝謝,我正在使用SQL server 2012 –

回答

1

如果你想要的輸出,你甚至都不需要啓動一個表:

with cte as (
     select 1 as col1, 2 as col2, 3 as col3, 4 as col4, 5 as col5 
     union all 
     select 5 + col1, 5 + col2, 5 + col3, 5 + col4, 5 + col5 
     from cte 
     where 5 + col1 <= 15 
    ) 
select * 
from cte; 
+0

請在Col4之後添加逗號 –

+0

@GaganSharma。 。 。謝謝。 –

+0

@ GordonLinoff ..最受歡迎。 –

2

假設你的表不只是擁有1連續編號爲n(如果這樣做,戈登的回答是更好), 這裏是做這件事:

首先,創建和填充示例表(保存這一步是在你未來的問題)

SELECT TOP 100 IDENTITY(int,1,1) AS col1 
    INTO table_name 
    FROM sys.objects s1  
    CROSS JOIN sys.objects s2 


DELETE 
FROM table_name 
WHERE col1 IN 
(
    SELECT TOP 67 col1 
    FROM table_name 
    ORDER BY NEWID() 
) 

(TABLE_NAME現在包含1到100之間33張隨機數)

使用一對夫婦的公共表表達式來獲取列數和行號:

;With Cols as 
(
    SELECT col1, 
      ROW_NUMBER() OVER(ORDER BY col1) % 5 ColNumber 
    FROM table_name 
), RowsAndCols as 
(
    SELECT col1, ColNumber, ROW_NUMBER() OVER(PARTITION BY ColNumber ORDER BY col1) As RowNumber 
    FROM Cols 
) 

和查詢:

SELECT c1.col1, c2.col1 As col2, c3.col1 As col3, c4.col1 As col4, c5.col1 As col5 
FROM RowsAndCols c1 
LEFT JOIN RowsAndCols c2 ON c1.RowNumber = c2.RowNumber AND c2.ColNumber = 2 
LEFT JOIN RowsAndCols c3 ON c1.RowNumber = c3.RowNumber AND c3.ColNumber = 3 
LEFT JOIN RowsAndCols c4 ON c1.RowNumber = c4.RowNumber AND c4.ColNumber = 4 
LEFT JOIN RowsAndCols c5 ON c1.RowNumber = c5.RowNumber AND c5.ColNumber = 0 
WHERE c1.ColNumber = 1 

注意我使用了左連接,所以萬一行數不是5的倍數,你會在最後一行的最後一列得到空值。

See a live demo on rexteser.

+0

感謝這個查詢它爲我工作很好。再次感謝@Zohar Peled。 –

+0

很高興幫助:-)。現在你所要做的就是選擇你要使用的答案,並將其標記爲已接受,這樣其他人就會知道問題已經解決。 –

4

使用基於把一個row_number(),以及用於列放置使用modulo %條件聚合:

測試設置:

select n into dbo.numbers from (values 
    (1), (2), (3), (4), (5), (6), (7), (8), (9),(10) 
,(11),(12),(13),(14),(15),(16),(17),(18),(19),(20) 
) t(n) 
delete from dbo.numbers where n in (12,13,17); 

查詢:

select 
    col1 = sum(case when rn%5=0 then n end) 
    , col2 = sum(case when rn%5=1 then n end) 
    , col3 = sum(case when rn%5=2 then n end) 
    , col4 = sum(case when rn%5=3 then n end) 
    , col5 = sum(case when rn%5=4 then n end) 
from (
    select n, rn = row_number() over (order by n)-1 
    from dbo.numbers 
) t 
group by rn/5; 

rextester演示:http://rextester.com/UHKY16981

回報:

+------+------+------+------+------+ 
| col1 | col2 | col3 | col4 | col5 | 
+------+------+------+------+------+ 
| 1 | 2 | 3 | 4 | 5 | 
| 6 | 7 | 8 | 9 | 10 | 
| 11 | 14 | 15 | 16 | 18 | 
| 19 | 20 | NULL | NULL | NULL | 
+------+------+------+------+------+ 

同樣的概念,但使用pivot()代替條件聚集返回相同的結果。

select 
    col1 = [0] 
    , col2 = [1] 
    , col3 = [2] 
    , col4 = [3] 
    , col5 = [4] 
from (
    select n 
    , rn = (row_number() over (order by n)-1)%5 
    , grp = (row_number() over (order by n)-1)/5 
    from dbo.numbers 
) t 
pivot (sum(n) for rn in ([0],[1],[2],[3],[4])) p; 
+0

我的回答比較好。我從條件聚合開始,但不知怎的,我沒有完全弄清楚,所以我選擇了不同的解決方案。 –

+0

非常感謝你的工作正常 –

+0

@sankard樂意幫忙! – SqlZim

6

另一種選擇是Dynamic Pivot。

這將創建N列。

Declare @nCols int = 5 

Declare @SQL varchar(max) = ' 
Declare @nCols int = '+str(@nCols,5)+' 
Select * 
From (
     Select RowNr = ((row_number() over (order by col1)-1)/@nCols)+1 
       ,ColNr = concat(''col-'',isnull(nullif((row_number() over (order by col1))%@nCols,0),@nCols)) 
       ,Value = col1 
     From YourTable 
    ) A 
Pivot (max(Value) For ColNr in (' + Stuff((Select Top (@nCols) ','+QuoteName(concat('col-',Row_Number() Over (Order By (Select NULL)))) From YourTable For XML Path('')) ,1,1,'') + ')) p' 
Exec(@SQL); 
--Print @SQL 

返回

enter image description here

如果@nCols = 3,則結果是:

enter image description here

編輯全參數驅動版本

這個版本可以提供

  1. 列數@NbrCols(同上)
  2. 來源@FromSrc,這是表名或SQL字符串中的()即(Select ...)
  3. 列名@ColName [透視@ColName
  4. 的科拉姆前綴@ColPrfx'Col-'甚至''

Declare @NbrCols int = 5 
Declare @FromSrc varchar(max) = 'YourTable' -- Or SQL '(Select col ...)' 
Declare @ColName varchar(100) = 'col1' 
Declare @ColPrfx varchar(100) = 'Col-' 

Declare @SQL varchar(max) = ' 
Declare @NbrCols int = '+str(@NbrCols,5)+' 
Select * 
From (
     Select Row = ((row_number() over (order by '+quotename(@ColName)+')-1)/@NbrCols)+1 
       ,Col = concat('''[email protected]+''',isnull(nullif((row_number() over (order by '+quotename(@ColName)+'))%@NbrCols,0),@NbrCols)) 
       ,Val = '+quotename(@ColName)+' 
     From '[email protected]+' A1 
    ) A 
Pivot (max(Val) For Col in (' + Stuff((Select Top (@NbrCols) ','+QuoteName(concat(@ColPrfx,Row_Number() Over (Order By (Select NULL)))) From master..spt_values For XML Path('')) ,1,1,'') + ')) p' 
Exec(@SQL); 
--Print @SQL 
+0

這可能是最好的答案,因爲OP要求提供n列。得到我的投票。 –

+0

我真的很喜歡這個答案,所以+1,但我會建議'RowNr'可以簡化而不是使用窗口函數 通過稍微修改您的查詢: [dbfiddle.uk demo](http:// dbfiddle .uk /?rdbms = sqlserver_2016&fiddle = a9614cd9a4aab10ceb2d4a5beabd4ed2) [rextester demo](http://rextester.com/YOXE25505),執行計劃比較簡單,沒有窗口後臺打印,儘管我沒有測試過是否可以有任何顯着的性能與較大的數據集一起使用時有所不同。 – SqlZim

+1

@SqlZim我正在看你的解決方案,並思考相同。稍後會進行更新 –