我在同一列中大约有28条记录(是动态的,有时记录数是奇数,有时是偶数)。
想根据一个变量将它们分成多列。每列中应该有5或6条记录。
注意:这5或6条记录是变量,应更改。
示例输入表:
Col1
-----
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
所需的输出表将是:
Col1 col2 col3 col4 col5
-------------------------------------
A F K P U
B G L Q V
C H M R W
D I N S X
E J O T Y
Z
这是我尝试过的,这两个不同的查询提供了不同的结果:
select Col1
from Table1 where Col1 is not null
order by [col1] asc
--This provides all records
WITH CTE AS
(
SELECT [Col1],
(ROW_NUMBER() OVER (ORDER BY Col1) -1)%5 AS Col,
(ROW_NUMBER() OVER (ORDER BY Col1) -1)/5 AS Row
FROM Table1 where Col1 is not null
)
SELECT [0], [1], [2], [3], [4]
FROM CTE
PIVOT (MAX([COL1]) FOR Col IN ([0], [1], [2], [3], [4])) AS Pvt
ORDER BY Row
-在这种情况下,缺少记录(当记录数很高时,因为记录数可以动态增加)
WITH CTE AS
(
SELECT [Col1],
(ROW_NUMBER() OVER (ORDER BY Col1) -1)%5 AS Col,
(ROW_NUMBER() OVER (ORDER BY Col1) -1)/5 AS Row
FROM Table1 where Col1 is not null
)
SELECT [0], [1]
FROM CTE
PIVOT (MAX([COL1]) FOR Col IN ([0], [1])) AS Pvt
ORDER BY Row
我在做什么错?如何获得所需的输出?谢谢。
答案 0 :(得分:3)
您需要首先为每条记录分配一列,这可以通过NTILE()
完成:
WITH Table1 AS
(
SELECT TOP 26 Col1 = CHAR(64 + ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
)
SELECT [Col1],
5 - NTILE(5) OVER(ORDER BY Col1 DESC) AS Col
FROM Table1 ;
给予:
Col1 Col
---------
Z 4
Y 4
X 4
W 4
V 4
U 4
T 3
....
Y 4
Z 4
请注意,要从最后一列开始填充,您必须以相反的顺序分配列(ORDER BY Col1 DESC
),然后从总列数中扣除。
然后,您可以通过按列顺序进行排序:
WITH Table1 AS
(
SELECT TOP 26 Col1 = CHAR(64 + ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
)
SELECT Col1, Col, ROW_NUMBER() OVER(PARTITION BY Col ORDER BY Col1) AS Row
FROM ( SELECT [Col1],
5 - NTILE(5) OVER(ORDER BY Col1 DESC) AS Col
FROM Table1
) c;
给予:
Col1 Col Row
--------------------
A 0 1
B 0 2
C 0 3
D 0 4
E 0 5
F 1 1
G 1 2
然后您可以应用数据透视:
WITH Table1 AS
(
SELECT TOP 26 Col1 = CHAR(64 + ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
), CTE AS
(
SELECT Col1, COL, ROW_NUMBER() OVER(PARTITION BY Col ORDER BY Col1) AS Row
FROM ( SELECT [Col1],
5 - NTILE(5) OVER(ORDER BY Col1 DESC) AS Col
FROM Table1
) c
)
SELECT [0], [1], [2], [3], [4]
FROM CTE
PIVOT (MAX([COL1]) FOR Col IN ([0], [1], [2], [3], [4])) AS Pvt
ORDER BY Row;
给予:
0 1 2 3 4
-------------------------------------
A F K P U
B G L Q V
C H M R W
D I N S X
E J O T Y
NULL NULL NULL NULL Z
添加
我已经建立了一个示例表,并使用了带有动态SQL的过程来简化重用,以演示该解决方案,对于我来说,它似乎可以正常工作。
设置
-- SET UP TABLE AND INSERT RANDOM VALUES
IF OBJECT_ID(N'tempdb..#Table1', 'U') IS NOT NULL
DROP TABLE #Table1;
CREATE TABLE #Table1 (Col1 CHAR(2));
INSERT #Table1 (Col1)
SELECT CONCAT(Letter, Number)
FROM (SELECT TOP 26 Letter = CHAR(64 + ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects) l
CROSS JOIN (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)) n (Number);
GO
IF OBJECT_ID(N'tempdb..#GenerateMatrix', 'P') IS NOT NULL
DROP PROCEDURE #GenerateMatrix;
GO
CREATE PROCEDURE #GenerateMatrix @Records INT, @Columns INT
AS
BEGIN
-- GENERATE COLUMNS FOR PIVOT AND SELECT
DECLARE @ColSQL NVARCHAR(MAX) =
STUFF((SELECT TOP (@Columns)
CONCAT(',', QUOTENAME(ROW_NUMBER() OVER(ORDER BY Col1) - 1))
FROM #Table1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
-- FOR @Cols = 5 Generates "[0],[1],[2],[3],[4]"
DECLARE @SQL NVARCHAR(MAX) =
CONCAT('SELECT ', @ColSQL, '
FROM (SELECT Col1, Col, Row = ROW_NUMBER() OVER(PARTITION BY Col ORDER BY Col1)
FROM ( SELECT [Col1], Col = @Columns - NTILE(@Columns) OVER(ORDER BY Col1 DESC)
FROM (SELECT TOP (@Records) Col1 FROM #Table1 Col1) t
) c) c
PIVOT (MAX([COL1]) FOR Col IN (', @ColSQL, ')) AS Pvt
ORDER BY Row;');
EXECUTE sp_executesql @SQL, N'@Columns INT, @Records INT', @Columns = @Columns, @Records = @Records;
END
GO
测试1
EXECUTE #GenerateMatrix @Records = 26, @Columns = 5;
0 1 2 3 4
----------------------------------
A1 A6 B2 B7 C3
A2 A7 B3 B8 C4
A3 A8 B4 B9 C5
A4 A9 B5 C1 C6
A5 B1 B6 C2 C7
NULL NULL NULL NULL C8
测试2
EXECUTE #GenerateMatrix @Records = 8, @Columns = 4;
0 1 2 3
----------------------------
A1 A3 A5 A7
A2 A4 A6 A8
测试3
EXECUTE #GenerateMatrix @Records = 40, @Columns = 8;
0 1 2 3 4 5 6 7
-----------------------------------------------------------
A1 A6 B2 B7 C3 C8 D4 D9
A2 A7 B3 B8 C4 C9 D5 E1
A3 A8 B4 B9 C5 D1 D6 E2
A4 A9 B5 C1 C6 D2 D7 E3
A5 B1 B6 C2 C7 D3 D8 E4
测试4
EXECUTE #GenerateMatrix @Records = 50, @Columns = 6;
0 1 2 3 4 5
---------------------------------------
A1 A9 B8 C7 D6 E6
A2 B1 B9 C8 D7 E7
A3 B2 C1 C9 D8 E8
A4 B3 C2 D1 D9 E9
A5 B4 C3 D2 E1 F1
A6 B5 C4 D3 E2 F2
A7 B6 C5 D4 E3 F3
A8 B7 C6 D5 E4 F4
NULL NULL NULL NULL E5 F5
在任何测试中都没有记录丢失,也没有行只有零值的行。
答案 1 :(得分:1)
凭经验,我能够提出以下数据透视查询:
WITH cte AS (
SELECT Col1, ROW_NUMBER() OVER (ORDER BY Col1) rn
FROM yourTable
)
SELECT
MAX(CASE WHEN (rn-1) / 5 = 0 THEN Col1 END) AS col1,
MAX(CASE WHEN (rn-1) / 5 = 1 THEN Col1 END) AS col2,
MAX(CASE WHEN (rn-1) / 5 = 2 THEN Col1 END) AS col3,
MAX(CASE WHEN (rn-1) / 5 = 3 THEN Col1 END) AS col4,
MAX(CASE WHEN (rn-1) / 5 = 4 THEN Col1 END) AS co15
FROM cte
GROUP BY
(rn-1) % 5;
这里的想法是,每个组(一行)由当前行号在模数5的哪一点确定。列或枢轴取决于当前行号的5的多少倍。
答案 2 :(得分:0)
您在做错什么了,在Col
中获得了五个值,
(ROW_NUMBER() OVER (ORDER BY Col1) -1)%5 AS Col,
但其中只有2个是PIVOTing。
PIVOT (MAX([COL1]) FOR Col IN ([0], [1])) AS Pvt
因此,您将忽略所有具有值2、3和4的Col
。