我有一个SQL Server表table_name,如:
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-server查询中获取此输出。
答案 0 :(得分: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
<强>返回强>
如果@nCols = 3,则结果为:
编辑完全参数驱动的版本
此版本可以提供
@NbrCols
(与上述相同)@FromSrc
,即表格名称或()中的SQL字符串,即(Select ...)
@ColName
到Pivot @ColName
@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('''+@ColPrfx+''',isnull(nullif((row_number() over (order by '+quotename(@ColName)+'))%@NbrCols,0),@NbrCols))
,Val = '+quotename(@ColName)+'
From '+@FromSrc+' 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
答案 1 :(得分: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;
答案 2 :(得分:2)
假设你的表不是简单地保持从1到n的连续数字(如果确实如此,Gordon的回答更好), 这是一种方法:
首先,创建并填充样本表(请保存是您未来问题中的此步骤)
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现在包含33个1到100之间的随机数)
使用几个公用表表达式来获取列号和行号:
;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的倍数,你将在最后一行的最后一列中得到空值。
答案 3 :(得分: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;